UNPKG

@hxui/angular

Version:

This README includes the steps that are necessary to import the HxUi-angular into a project or to contribute with development.

520 lines (519 loc) 51.7 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ import { Directive, ElementRef, EventEmitter, HostListener, Input, Output, Renderer2, TemplateRef, ViewContainerRef } from '@angular/core'; import { NgControl } from '@angular/forms'; import { TypeaheadContainerComponent } from './typeahead-container.component'; import { getValueFromObject, latinize, tokenize } from './typeahead-utils'; import { Observable, from } from 'rxjs'; import { debounceTime, mergeMap, filter, toArray } from 'rxjs/operators'; import { TypeaheadMatch } from './typeahead-match.class'; import { ComponentLoaderFactory } from '../component-loader/component-loader.factory'; export class TypeaheadDirective { /** * @param {?} control * @param {?} viewContainerRef * @param {?} element * @param {?} renderer * @param {?} cis */ constructor(control, viewContainerRef, element, renderer, cis) { /** * minimal no of characters that needs to be entered before typeahead kicks-in. When set to 0, typeahead shows on focus with full list of options (limited as normal by typeaheadOptionsLimit) */ this.typeaheadMinLength = void 0; /** * should be used only in case of typeahead attribute is array. If true - loading of options will be async, otherwise - sync. true make sense if options array is large. */ this.typeaheadAsync = void 0; /** * match latin symbols. If true the word súper would match super and vice versa. */ this.typeaheadLatinize = true; /** * break words with spaces. If true the text "exact phrase" here match would match with match exact phrase here but not with phrase here exact match (kind of "google style"). */ this.typeaheadSingleWords = true; /** * should be used only in case typeaheadSingleWords attribute is true. Sets the word delimiter to break words. Defaults to space. */ this.typeaheadWordDelimiters = ' '; /** * should be used only in case typeaheadSingleWords attribute is true. Sets the word delimiter to match exact phrase. Defaults to simple and double quotes. */ this.typeaheadPhraseDelimiters = '\'"'; /** * fired when 'busy' state of this component was changed, fired on async mode only, returns boolean */ this.typeaheadLoading = new EventEmitter(); /** * fired on every key event and returns true in case of matches are not detected */ this.typeaheadNoResults = new EventEmitter(); /** * fired when option was selected, return object with data of this option */ this.typeaheadOnSelect = new EventEmitter(); /** * fired when blur event occurres. returns the active item */ this.typeaheadOnBlur = new EventEmitter(); this.isTypeaheadOptionsListActive = false; this.keyUpEventEmitter = new EventEmitter(); this.placement = 'bottom-left'; this.element = element; this.ngControl = control; this.viewContainerRef = viewContainerRef; this.renderer = renderer; this._typeahead = cis .createLoader(element, viewContainerRef, renderer); } /** * @param {?} e * @return {?} */ onChange(e) { if (this._container) { // esc if (e.keyCode === 27) { this.hide(); return; } // up if (e.keyCode === 38) { this._container.prevActiveMatch(); return; } // down if (e.keyCode === 40) { this._container.nextActiveMatch(); return; } // enter if (e.keyCode === 13) { this._container.selectActiveMatch(); return; } } // For `<input>`s, use the `value` property. For others that don't have a // `value` (such as `<span contenteditable="true">`, use `innerText`. const /** @type {?} */ value = e.target.value !== undefined ? e.target.value : e.target.innerText; if (value.trim().length >= this.typeaheadMinLength) { this.typeaheadLoading.emit(true); this.keyUpEventEmitter.emit(e.target.value); } else { this.typeaheadLoading.emit(false); this.typeaheadNoResults.emit(false); this.hide(); } } /** * @return {?} */ onFocus() { if (this.typeaheadMinLength === 0) { this.typeaheadLoading.emit(true); this.keyUpEventEmitter.emit(''); } } /** * @return {?} */ onBlur() { if (this._container && !this._container.isFocused) { this.typeaheadOnBlur.emit(this._container.active); this.hide(); } } /** * @param {?} e * @return {?} */ onKeydown(e) { // no container - no problems if (!this._container) { return; } // if items is visible - prevent form submition if (e.keyCode === 13) { e.preventDefault(); return; } } /** * @return {?} */ ngOnInit() { this.typeaheadOptionsLimit = this.typeaheadOptionsLimit || 20; this.typeaheadMinLength = this.typeaheadMinLength === void 0 ? 1 : this.typeaheadMinLength; this.typeaheadWaitMs = this.typeaheadWaitMs || 0; // async should be false in case of array if (this.typeaheadAsync === undefined && !(this.typeahead instanceof Observable)) { this.typeaheadAsync = false; } if (this.typeahead instanceof Observable) { this.typeaheadAsync = true; } if (this.typeaheadAsync) { this.asyncActions(); } else { this.syncActions(); } } /** * @param {?} match * @return {?} */ changeModel(match) { const /** @type {?} */ valueStr = match.value; this.ngControl.viewToModelUpdate(valueStr); (/** @type {?} */ (this.ngControl.control)).setValue(valueStr); this.hide(); } /** * @return {?} */ get matches() { return this._matches; } /** * @return {?} */ show() { this._typeahead .attach(TypeaheadContainerComponent) .to(this.container) .position({ attachment: 'bottom left' }) .show({ typeaheadRef: this, placement: this.placement, animation: false }); this._container = this._typeahead.instance; this._container.parent = this; // This improves the speed as it won't have to be done for each list item const /** @type {?} */ normalizedQuery = (this.typeaheadLatinize ? latinize(this.ngControl.control.value) : this.ngControl.control.value).toString() .toLowerCase(); this._container.query = this.typeaheadSingleWords ? tokenize(normalizedQuery, this.typeaheadWordDelimiters, this.typeaheadPhraseDelimiters) : normalizedQuery; this._container.matches = this._matches; this.element.nativeElement.focus(); } /** * @return {?} */ hide() { if (this._typeahead.isShown) { this._typeahead.hide(); this._container = null; } } /** * @return {?} */ ngOnDestroy() { this._typeahead.dispose(); } /** * @return {?} */ asyncActions() { this.keyUpEventEmitter.pipe(debounceTime(this.typeaheadWaitMs), mergeMap(() => this.typeahead)).subscribe((matches) => { this.finalizeAsyncCall(matches); }, (err) => { console.error(err); }); } /** * @return {?} */ syncActions() { this.keyUpEventEmitter.pipe(debounceTime(this.typeaheadWaitMs), mergeMap((value) => { const /** @type {?} */ normalizedQuery = this.normalizeQuery(value); return from(this.typeahead).pipe(filter((option) => { return option && this.testMatch(this.normalizeOption(option), normalizedQuery); }), toArray()); })) .subscribe((matches) => { this.finalizeAsyncCall(matches); }, (err) => { console.error(err); }); } /** * @param {?} option * @return {?} */ normalizeOption(option) { const /** @type {?} */ optionValue = getValueFromObject(option, this.typeaheadOptionField); const /** @type {?} */ normalizedOption = this.typeaheadLatinize ? latinize(optionValue) : optionValue; return normalizedOption.toLowerCase(); } /** * @param {?} value * @return {?} */ normalizeQuery(value) { // If singleWords, break model here to not be doing extra work on each // iteration let /** @type {?} */ normalizedQuery = (this.typeaheadLatinize ? latinize(value) : value) .toString() .toLowerCase(); normalizedQuery = this.typeaheadSingleWords ? tokenize(normalizedQuery, this.typeaheadWordDelimiters, this.typeaheadPhraseDelimiters) : normalizedQuery; return normalizedQuery; } /** * @param {?} match * @param {?} test * @return {?} */ testMatch(match, test) { let /** @type {?} */ spaceLength; if (typeof test === 'object') { spaceLength = test.length; for (let /** @type {?} */ i = 0; i < spaceLength; i += 1) { if (test[i].length > 0 && match.indexOf(test[i]) < 0) { return false; } } return true; } else { return match.indexOf(test) >= 0; } } /** * @param {?} matches * @return {?} */ finalizeAsyncCall(matches) { this.prepareMatches(matches); this.typeaheadLoading.emit(false); this.typeaheadNoResults.emit(!this.hasMatches()); if (!this.hasMatches()) { this.hide(); return; } if (this._container) { // This improves the speed as it won't have to be done for each list item const /** @type {?} */ normalizedQuery = (this.typeaheadLatinize ? latinize(this.ngControl.control.value) : this.ngControl.control.value).toString() .toLowerCase(); this._container.query = this.typeaheadSingleWords ? tokenize(normalizedQuery, this.typeaheadWordDelimiters, this.typeaheadPhraseDelimiters) : normalizedQuery; this._container.matches = this._matches; } else { this.show(); } } /** * @param {?} options * @return {?} */ prepareMatches(options) { const /** @type {?} */ limited = options.slice(0, this.typeaheadOptionsLimit); if (this.typeaheadGroupField) { let /** @type {?} */ matches = []; // extract all group names const /** @type {?} */ groups = limited .map((option) => getValueFromObject(option, this.typeaheadGroupField)) .filter((v, i, a) => a.indexOf(v) === i); groups.forEach((group) => { // add group header to array of matches matches.push(new TypeaheadMatch(group, group, true)); // add each item of group to array of matches matches = matches.concat(limited .filter((option) => getValueFromObject(option, this.typeaheadGroupField) === group) .map((option) => new TypeaheadMatch(option, getValueFromObject(option, this.typeaheadOptionField)))); }); this._matches = matches; } else { this._matches = limited.map((option) => new TypeaheadMatch(option, getValueFromObject(option, this.typeaheadOptionField))); } } /** * @return {?} */ hasMatches() { return this._matches.length > 0; } } TypeaheadDirective.decorators = [ { type: Directive, args: [{ selector: '[typeahead]', exportAs: 'hx-typeahead' },] }, ]; /** @nocollapse */ TypeaheadDirective.ctorParameters = () => [ { type: NgControl, }, { type: ViewContainerRef, }, { type: ElementRef, }, { type: Renderer2, }, { type: ComponentLoaderFactory, }, ]; TypeaheadDirective.propDecorators = { "typeahead": [{ type: Input },], "typeaheadMinLength": [{ type: Input },], "typeaheadWaitMs": [{ type: Input },], "typeaheadOptionsLimit": [{ type: Input },], "typeaheadOptionField": [{ type: Input },], "typeaheadGroupField": [{ type: Input },], "typeaheadAsync": [{ type: Input },], "typeaheadLatinize": [{ type: Input },], "typeaheadSingleWords": [{ type: Input },], "typeaheadWordDelimiters": [{ type: Input },], "typeaheadPhraseDelimiters": [{ type: Input },], "typeaheadItemTemplate": [{ type: Input },], "optionsListTemplate": [{ type: Input },], "typeaheadLoading": [{ type: Output },], "typeaheadNoResults": [{ type: Output },], "typeaheadOnSelect": [{ type: Output },], "typeaheadOnBlur": [{ type: Output },], "container": [{ type: Input },], "onChange": [{ type: HostListener, args: ['keyup', ['$event'],] },], "onFocus": [{ type: HostListener, args: ['focus',] },], "onBlur": [{ type: HostListener, args: ['blur',] },], "onKeydown": [{ type: HostListener, args: ['keydown', ['$event'],] },], }; function TypeaheadDirective_tsickle_Closure_declarations() { /** @type {!Array<{type: !Function, args: (undefined|!Array<?>)}>} */ TypeaheadDirective.decorators; /** * @nocollapse * @type {function(): !Array<(null|{type: ?, decorators: (undefined|!Array<{type: !Function, args: (undefined|!Array<?>)}>)})>} */ TypeaheadDirective.ctorParameters; /** @type {!Object<string,!Array<{type: !Function, args: (undefined|!Array<?>)}>>} */ TypeaheadDirective.propDecorators; /** * options source, can be Array of strings, objects or an Observable for external matching process * @type {?} */ TypeaheadDirective.prototype.typeahead; /** * minimal no of characters that needs to be entered before typeahead kicks-in. When set to 0, typeahead shows on focus with full list of options (limited as normal by typeaheadOptionsLimit) * @type {?} */ TypeaheadDirective.prototype.typeaheadMinLength; /** * minimal wait time after last character typed before typeahead kicks-in * @type {?} */ TypeaheadDirective.prototype.typeaheadWaitMs; /** * maximum length of options items list * @type {?} */ TypeaheadDirective.prototype.typeaheadOptionsLimit; /** * when options source is an array of objects, the name of field that contains the options value, we use array item as option in case of this field is missing. Supports nested properties and methods. * @type {?} */ TypeaheadDirective.prototype.typeaheadOptionField; /** * when options source is an array of objects, the name of field that contains the group value, matches are grouped by this field when set. * @type {?} */ TypeaheadDirective.prototype.typeaheadGroupField; /** * should be used only in case of typeahead attribute is array. If true - loading of options will be async, otherwise - sync. true make sense if options array is large. * @type {?} */ TypeaheadDirective.prototype.typeaheadAsync; /** * match latin symbols. If true the word súper would match super and vice versa. * @type {?} */ TypeaheadDirective.prototype.typeaheadLatinize; /** * break words with spaces. If true the text "exact phrase" here match would match with match exact phrase here but not with phrase here exact match (kind of "google style"). * @type {?} */ TypeaheadDirective.prototype.typeaheadSingleWords; /** * should be used only in case typeaheadSingleWords attribute is true. Sets the word delimiter to break words. Defaults to space. * @type {?} */ TypeaheadDirective.prototype.typeaheadWordDelimiters; /** * should be used only in case typeaheadSingleWords attribute is true. Sets the word delimiter to match exact phrase. Defaults to simple and double quotes. * @type {?} */ TypeaheadDirective.prototype.typeaheadPhraseDelimiters; /** * used to specify a custom item template. Template variables exposed are called item and index; * @type {?} */ TypeaheadDirective.prototype.typeaheadItemTemplate; /** * used to specify a custom options list template. Template variables: matches, itemTemplate, query * @type {?} */ TypeaheadDirective.prototype.optionsListTemplate; /** * fired when 'busy' state of this component was changed, fired on async mode only, returns boolean * @type {?} */ TypeaheadDirective.prototype.typeaheadLoading; /** * fired on every key event and returns true in case of matches are not detected * @type {?} */ TypeaheadDirective.prototype.typeaheadNoResults; /** * fired when option was selected, return object with data of this option * @type {?} */ TypeaheadDirective.prototype.typeaheadOnSelect; /** * fired when blur event occurres. returns the active item * @type {?} */ TypeaheadDirective.prototype.typeaheadOnBlur; /** * A selector specifying the element the typeahead should be appended to. * Currently only supports "body". * @type {?} */ TypeaheadDirective.prototype.container; /** * if false don't focus the input element the typeahead directive is associated with on selection * @type {?} */ TypeaheadDirective.prototype._container; /** @type {?} */ TypeaheadDirective.prototype.isTypeaheadOptionsListActive; /** @type {?} */ TypeaheadDirective.prototype.keyUpEventEmitter; /** @type {?} */ TypeaheadDirective.prototype._matches; /** @type {?} */ TypeaheadDirective.prototype.placement; /** @type {?} */ TypeaheadDirective.prototype.ngControl; /** @type {?} */ TypeaheadDirective.prototype.viewContainerRef; /** @type {?} */ TypeaheadDirective.prototype.element; /** @type {?} */ TypeaheadDirective.prototype.renderer; /** @type {?} */ TypeaheadDirective.prototype._typeahead; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZWFoZWFkLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0BoeHVpL2FuZ3VsYXIvIiwic291cmNlcyI6WyJsaWIvdHlwZWFoZWFkL3R5cGVhaGVhZC5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUN4RCxNQUFNLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxnQkFBZ0IsRUFDakQsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFlLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3hELE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzlFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFM0UsT0FBTyxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDeEMsT0FBTyxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw4Q0FBOEMsQ0FBQztBQUl0RixNQUFNOzs7Ozs7OztnQkFpSmUsT0FBa0IsRUFBRSxnQkFBa0MsRUFBRSxPQUFtQixFQUFFLFFBQW1CLEVBQUUsR0FBMkI7Ozs7a0NBN0luRyxLQUFLLENBQUM7Ozs7OEJBVVQsS0FBSyxDQUFDOzs7O2lDQUVaLElBQUk7Ozs7b0NBRUQsSUFBSTs7Ozt1Q0FFRCxHQUFHOzs7O3lDQUVELEtBQUs7Ozs7Z0NBT1UsSUFBSSxZQUFZLEVBQUU7Ozs7a0NBRWhCLElBQUksWUFBWSxFQUFFOzs7O2lDQUVaLElBQUksWUFBWSxFQUFFOzs7OytCQUUv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LEtBQUs7Z0NBRUwsS0FBSztzQ0FFTCxLQUFLO3FDQUVMLEtBQUs7b0NBRUwsS0FBSzsrQkFFTCxLQUFLO2tDQUVMLEtBQUs7cUNBRUwsS0FBSzt3Q0FFTCxLQUFLOzBDQUVMLEtBQUs7c0NBRUwsS0FBSztvQ0FFTCxLQUFLO2lDQUdMLE1BQU07bUNBRU4sTUFBTTtrQ0FFTixNQUFNO2dDQUVOLE1BQU07MEJBTU4sS0FBSzt5QkErQkwsWUFBWSxTQUFDLE9BQU8sRUFBRSxDQUFDLFFBQVEsQ0FBQzt3QkEyQ2hDLFlBQVksU0FBQyxPQUFPO3VCQVFwQixZQUFZLFNBQUMsTUFBTTswQkFRbkIsWUFBWSxTQUFDLFNBQVMsRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgRGlyZWN0aXZlLCBFbGVtZW50UmVmLCBFdmVudEVtaXR0ZXIsIEhvc3RMaXN0ZW5lciwgSW5wdXQsIE9uRGVzdHJveSwgT25Jbml0LFxyXG4gIE91dHB1dCwgUmVuZGVyZXIyLCBUZW1wbGF0ZVJlZiwgVmlld0NvbnRhaW5lclJlZlxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBGb3JtQ29udHJvbCwgTmdDb250cm9sIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xyXG5pbXBvcnQgeyBUeXBlYWhlYWRDb250YWluZXJDb21wb25lbnQgfSBmcm9tICcuL3R5cGVhaGVhZC1jb250YWluZXIuY29tcG9uZW50JztcclxuaW1wb3J0IHsgZ2V0VmFsdWVGcm9tT2JqZWN0LCBsYXRpbml6ZSwgdG9rZW5pemUgfSBmcm9tICcuL3R5cGVhaGVhZC11dGlscyc7XHJcblxyXG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBmcm9tIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IGRlYm91bmNlVGltZSwgbWVyZ2VNYXAsIGZpbHRlciwgdG9BcnJheSB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgVHlwZWFoZWFkTWF0Y2ggfSBmcm9tICcuL3R5cGVhaGVhZC1tYXRjaC5jbGFzcyc7XHJcbmltcG9ydCB7IENvbXBvbmVudExvYWRlckZhY3RvcnkgfSBmcm9tICcuLi9jb21wb25lbnQtbG9hZGVyL2NvbXBvbmVudC1sb2FkZXIuZmFjdG9yeSc7XHJcbmltcG9ydCB7IENvbXBvbmVudExvYWRlciB9IGZyb20gJy4uL2NvbXBvbmVudC1sb2FkZXIvY29tcG9uZW50LWxvYWRlci5jbGFzcyc7XHJcblxyXG5ARGlyZWN0aXZlKHtzZWxlY3RvcjogJ1t0eXBlYWhlYWRdJywgZXhwb3J0QXM6ICdoeC10eXBlYWhlYWQnfSlcclxuZXhwb3J0IGNsYXNzIFR5cGVhaGVhZERpcmVjdGl2ZSBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcclxuICAvKiogb3B0aW9ucyBzb3VyY2UsIGNhbiBiZSBBcnJheSBvZiBzdHJpbmdzLCBvYmplY3RzIG9yIGFuIE9ic2VydmFibGUgZm9yIGV4dGVybmFsIG1hdGNoaW5nIHByb2Nlc3MgKi9cclxuICBASW5wdXQoKSBwdWJsaWMgdHlwZWFoZWFkOiBhbnk7XHJcbiAgLyoqIG1pbmltYWwgbm8gb2YgY2hhcmFjdGVycyB0aGF0IG5lZWRzIHRvIGJlIGVudGVyZWQgYmVmb3JlIHR5cGVhaGVhZCBraWNrcy1pbi4gV2hlbiBzZXQgdG8gMCwgdHlwZWFoZWFkIHNob3dzIG9uIGZvY3VzIHdpdGggZnVsbCBsaXN0IG9mIG9wdGlvbnMgKGxpbWl0ZWQgYXMgbm9ybWFsIGJ5IHR5cGVhaGVhZE9wdGlvbnNMaW1pdCkgKi9cclxuICBASW5wdXQoKSBwdWJsaWMgdHlwZWFoZWFkTWluTGVuZ3RoOiBudW1iZXIgPSB2b2lkIDA7XHJcbiAgLyoqIG1pbmltYWwgd2FpdCB0aW1lIGFmdGVyIGxhc3QgY2hhcmFjdGVyIHR5cGVkIGJlZm9yZSB0eXBlYWhlYWQga2lja3MtaW4gKi9cclxuICBASW5wdXQoKSBwdWJsaWMgdHlwZWFoZWFkV2FpdE1zOiBudW1iZXI7XHJcbiAgLyoqIG1heGltdW0gbGVuZ3RoIG9mIG9wdGlvbnMgaXRlbXMgbGlzdCAqL1xyXG4gIEBJbnB1dCgpIHB1YmxpYyB0eXBlYWhlYWRPcHRpb25zTGltaXQ6IG51bWJlcjtcclxuICAvKiogd2hlbiBvcHRpb25zIHNvdXJjZSBpcyBhbiBhcnJheSBvZiBvYmplY3RzLCB0aGUgbmFtZSBvZiBmaWVsZCB0aGF0IGNvbnRhaW5zIHRoZSBvcHRpb25zIHZhbHVlLCB3ZSB1c2UgYXJyYXkgaXRlbSBhcyBvcHRpb24gaW4gY2FzZSBvZiB0aGlzIGZpZWxkIGlzIG1pc3NpbmcuIFN1cHBvcnRzIG5lc3RlZCBwcm9wZXJ0aWVzIGFuZCBtZXRob2RzLiAqL1xyXG4gIEBJbnB1dCgpIHB1YmxpYyB0eXBlYWhlYWRPcHRpb25GaWVsZDogc3RyaW5nO1xyXG4gIC8qKiB3aGVuIG9wdGlvbnMgc291cmNlIGlzIGFuIGFycmF5IG9mIG9iamVjdHMsIHRoZSBuYW1lIG9mIGZpZWxkIHRoYXQgY29udGFpbnMgdGhlIGdyb3VwIHZhbHVlLCBtYXRjaGVzIGFyZSBncm91cGVkIGJ5IHRoaXMgZmllbGQgd2hlbiBzZXQuICovXHJcbiAgQElucHV0KCkgcHVibGljIHR5cGVhaGVhZEdyb3VwRmllbGQ6IHN0cmluZztcclxuICAvKiogc2hvdWxkIGJlIHVzZWQgb25seSBpbiBjYXNlIG9mIHR5cGVhaGVhZCBhdHRyaWJ1dGUgaXMgYXJyYXkuIElmIHRydWUgLSBsb2FkaW5nIG9mIG9wdGlvbnMgd2lsbCBiZSBhc3luYywgb3RoZXJ3aXNlIC0gc3luYy4gdHJ1ZSBtYWtlIHNlbnNlIGlmIG9wdGlvbnMgYXJyYXkgaXMgbGFyZ2UuICovXHJcbiAgQElucHV0KCkgcHVibGljIHR5cGVhaGVhZEFzeW5jOiBib29sZWFuID0gdm9pZCAwO1xyXG4gIC8qKiBtYXRjaCBsYXRpbiBzeW1ib2xzLiBJZiB0cnVlIHRoZSB3b3JkIHPDunBlciB3b3VsZCBtYXRjaCBzdXBlciBhbmQgdmljZSB2ZXJzYS4gKi9cclxuICBASW5wdXQoKSBwdWJsaWMgdHlwZWFoZWFkTGF0aW5pemUgPSB0cnVlO1xyXG4gIC8qKiBicmVhayB3b3JkcyB3aXRoIHNwYWNlcy4gSWYgdHJ1ZSB0aGUgdGV4dCBcImV4YWN0IHBocmFzZVwiIGhlcmUgbWF0Y2ggd291bGQgbWF0Y2ggd2l0aCBtYXRjaCBleGFjdCBwaHJhc2UgaGVyZSBidXQgbm90IHdpdGggcGhyYXNlIGhlcmUgZXhhY3QgbWF0Y2ggKGtpbmQgb2YgXCJnb29nbGUgc3R5bGVcIikuICovXHJcbiAgQElucHV0KCkgcHVibGljIHR5cGVhaGVhZFNpbmdsZVdvcmRzID0gdHJ1ZTtcclxuICAvKiogc2hvdWxkIGJlIHVzZWQgb25seSBpbiBjYXNlIHR5cGVhaGVhZFNpbmdsZVdvcmRzIGF0dHJpYnV0ZSBpcyB0cnVlLiBTZXRzIHRoZSB3b3JkIGRlbGltaXRlciB0byBicmVhayB3b3Jkcy4gRGVmYXVsdHMgdG8gc3BhY2UuICovXHJcbiAgQElucHV0KCkgcHVibGljIHR5cGVhaGVhZFdvcmREZWxpbWl0ZXJzID0gJyAnO1xyXG4gIC8qKiBzaG91bGQgYmUgdXNlZCBvbmx5IGluIGNhc2UgdHlwZWFoZWFkU2luZ2xlV29yZHMgYXR0cmlidXRlIGlzIHRydWUuIFNldHMgdGhlIHdvcmQgZGVsaW1pdGVyIHRvIG1hdGNoIGV4YWN0IHBocmFzZS4gRGVmYXVsdHMgdG8gc2ltcGxlIGFuZCBkb3VibGUgcXVvdGVzLiAqL1xyXG4gIEBJbnB1dCgpIHB1YmxpYyB0eXBlYWhlYWRQaHJhc2VEZWxpbWl0ZXJzID0gJ1xcJ1wiJztcclxuICAvKiogdXNlZCB0byBzcGVjaWZ5IGEgY3VzdG9tIGl0ZW0gdGVtcGxhdGUuIFRlbXBsYXRlIHZhcmlhYmxlcyBleHBvc2VkIGFyZSBjYWxsZWQgaXRlbSBhbmQgaW5kZXg7ICovXHJcbiAgQElucHV0KCkgcHVibGljIHR5cGVhaGVhZEl0ZW1UZW1wbGF0ZTogVGVtcGxhdGVSZWY8YW55PjtcclxuICAvKiogdXNlZCB0byBzcGVjaWZ5IGEgY3VzdG9tIG9wdGlvbnMgbGlzdCB0ZW1wbGF0ZS4gVGVtcGxhdGUgdmFyaWFibGVzOiBtYXRjaGVzLCBpdGVtVGVtcGxhdGUsIHF1ZXJ5ICovXHJcbiAgQElucHV0KCkgcHVibGljIG9wdGlvbnNMaXN0VGVtcGxhdGU6IFRlbXBsYXRlUmVmPGFueT47XHJcblxyXG4gIC8qKiBmaXJlZCB3aGVuICdidXN5JyBzdGF0ZSBvZiB0aGlzIGNvbXBvbmVudCB3YXMgY2hhbmdlZCwgZmlyZWQgb24gYXN5bmMgbW9kZSBvbmx5LCByZXR1cm5zIGJvb2xlYW4gKi9cclxuICBAT3V0cHV0KCkgcHVibGljIHR5cGVhaGVhZExvYWRpbmc6IEV2ZW50RW1pdHRlcjxib29sZWFuPiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcclxuICAvKiogZmlyZWQgb24gZXZlcnkga2V5IGV2ZW50IGFuZCByZXR1cm5zIHRydWUgaW4gY2FzZSBvZiBtYXRjaGVzIGFyZSBub3QgZGV0ZWN0ZWQgKi9cclxuICBAT3V0cHV0KCkgcHVibGljIHR5cGVhaGVhZE5vUmVzdWx0czogRXZlbnRFbWl0dGVyPGJvb2xlYW4+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xyXG4gIC8qKiBmaXJlZCB3aGVuIG9wdGlvbiB3YXMgc2VsZWN0ZWQsIHJldHVybiBvYmplY3Qgd2l0aCBkYXRhIG9mIHRoaXMgb3B0aW9uICovXHJcbiAgQE91dHB1dCgpIHB1YmxpYyB0eXBlYWhlYWRPblNlbGVjdDogRXZlbnRFbWl0dGVyPFR5cGVhaGVhZE1hdGNoPiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcclxuICAvKiogZmlyZWQgd2hlbiBibHVyIGV2ZW50IG9jY3VycmVzLiByZXR1cm5zIHRoZSBhY3RpdmUgaXRlbSAqL1xyXG4gIEBPdXRwdXQoKSBwdWJsaWMgdHlwZWFoZWFkT25CbHVyOiBFdmVudEVtaXR0ZXI8YW55PiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQSBzZWxlY3RvciBzcGVjaWZ5aW5nIHRoZSBlbGVtZW50IHRoZSB0eXBlYWhlYWQgc2hvdWxkIGJlIGFwcGVuZGVkIHRvLlxyXG4gICAqIEN1cnJlbnRseSBvbmx5IHN1cHBvcnRzIFwiYm9keVwiLlxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIHB1YmxpYyBjb250YWluZXI6IHN0cmluZztcclxuXHJcbiAgLy8gbm90IHlldCBpbXBsZW1lbnRlZFxyXG4gIC8qKiBpZiBmYWxzZSByZXN0cmljdCBtb2RlbCB2YWx1ZXMgdG8gdGhlIG9uZXMgc2VsZWN0ZWQgZnJvbSB0aGUgcG9wdXAgb25seSB3aWxsIGJlIHByb3ZpZGVkICovXHJcbiAgLy8gQElucHV0KCkgcHJvdGVjdGVkIHR5cGVhaGVhZEVkaXRhYmxlOmJvb2xlYW47XHJcbiAgLyoqIGlmIGZhbHNlIHRoZSBmaXJzdCBtYXRjaCBhdXRvbWF0aWNhbGx5IHdpbGwgbm90IGJlIGZvY3VzZWQgYXMgeW91IHR5cGUgKi9cclxuICAvLyBASW5wdXQoKSBwcm90ZWN0ZWQgdHlwZWFoZWFkRm9jdXNGaXJzdDpib29sZWFuO1xyXG4gIC8qKiBmb3JtYXQgdGhlIG5nLW1vZGVsIHJlc3VsdCBhZnRlciBzZWxlY3Rpb24gKi9cclxuICAvLyBASW5wdXQoKSBwcm90ZWN0ZWQgdHlwZWFoZWFkSW5wdXRGb3JtYXR0ZXI6YW55O1xyXG4gIC8qKiBpZiB0cnVlIGF1dG9tYXRpY2FsbHkgc2VsZWN0IGFuIGl0ZW0gd2hlbiB0aGVyZSBpcyBvbmUgb3B0aW9uIHRoYXQgZXhhY3RseSBtYXRjaGVzIHRoZSB1c2VyIGlucHV0ICovXHJcbiAgLy8gQElucHV0KCkgcHJvdGVjdGVkIHR5cGVhaGVhZFNlbGVjdE9uRXhhY3Q6Ym9vbGVhbjtcclxuICAvKiogIGlmIHRydWUgc2VsZWN0IHRoZSBjdXJyZW50bHkgaGlnaGxpZ2h0ZWQgbWF0Y2ggb24gYmx1ciAqL1xyXG4gIC8vIEBJbnB1dCgpIHByb3RlY3RlZCB0eXBlYWhlYWRTZWxlY3RPbkJsdXI6Ym9vbGVhbjtcclxuICAvKiogIGlmIGZhbHNlIGRvbid0IGZvY3VzIHRoZSBpbnB1dCBlbGVtZW50IHRoZSB0eXBlYWhlYWQgZGlyZWN0aXZlIGlzIGFzc29jaWF0ZWQgd2l0aCBvbiBzZWxlY3Rpb24gKi9cclxuICAgIC8vIEBJbnB1dCgpIHByb3RlY3RlZCB0eXBlYWhlYWRGb2N1c09uU2VsZWN0OmJvb2xlYW47XHJcblxyXG4gIHB1YmxpYyBfY29udGFpbmVyOiBUeXBlYWhlYWRDb250YWluZXJDb21wb25lbnQ7XHJcbiAgcHVibGljIGlzVHlwZWFoZWFkT3B0aW9uc0xpc3RBY3RpdmUgPSBmYWxzZTtcclxuXHJcbiAgcHJvdGVjdGVkIGtleVVwRXZlbnRFbWl0dGVyOiBFdmVudEVtaXR0ZXI8YW55PiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcclxuICBwcm90ZWN0ZWQgX21hdGNoZXM6IFR5cGVhaGVhZE1hdGNoW107XHJcbiAgcHJvdGVjdGVkIHBsYWNlbWVudCA9ICdib3R0b20tbGVmdCc7XHJcbiAgLy8gcHJvdGVjdGVkIHBvcHVwOkNvbXBvbmVudFJlZjxUeXBlYWhlYWRDb250YWluZXJDb21wb25lbnQ+O1xyXG5cclxuICBwcm90ZWN0ZWQgbmdDb250cm9sOiBOZ0NvbnRyb2w7XHJcbiAgcHJvdGVjdGVkIHZpZXdDb250YWluZXJSZWY6IFZpZXdDb250YWluZXJSZWY7XHJcbiAgcHJvdGVjdGVkIGVsZW1lbnQ6IEVsZW1lbnRSZWY7XHJcbiAgcHJvdGVjdGVkIHJlbmRlcmVyOiBSZW5kZXJlcjI7XHJcblxyXG4gIHByaXZhdGUgX3R5cGVhaGVhZDogQ29tcG9uZW50TG9hZGVyPFR5cGVhaGVhZENvbnRhaW5lckNvbXBvbmVudD47XHJcblxyXG4gIEBIb3N0TGlzdGVuZXIoJ2tleXVwJywgWyckZXZlbnQnXSlcclxuICBwdWJsaWMgb25DaGFuZ2UoZTogYW55KTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5fY29udGFpbmVyKSB7XHJcbiAgICAgIC8vIGVzY1xyXG4gICAgICBpZiAoZS5rZXlDb2RlID09PSAyNykge1xyXG4gICAgICAgIHRoaXMuaGlkZSgpO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gdXBcclxuICAgICAgaWYgKGUua2V5Q29kZSA9PT0gMzgpIHtcclxuICAgICAgICB0aGlzLl9jb250YWluZXIucHJldkFjdGl2ZU1hdGNoKCk7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBkb3duXHJcbiAgICAgIGlmIChlLmtleUNvZGUgPT09IDQwKSB7XHJcbiAgICAgICAgdGhpcy5fY29udGFpbmVyLm5leHRBY3RpdmVNYXRjaCgpO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gZW50ZXJcclxuICAgICAgaWYgKGUua2V5Q29kZSA9PT0gMTMpIHtcclxuICAgICAgICB0aGlzLl9jb250YWluZXIuc2VsZWN0QWN0aXZlTWF0Y2goKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBGb3IgYDxpbnB1dD5gcywgdXNlIHRoZSBgdmFsdWVgIHByb3BlcnR5LiBGb3Igb3RoZXJzIHRoYXQgZG9uJ3QgaGF2ZSBhXHJcbiAgICAvLyBgdmFsdWVgIChzdWNoIGFzIGA8c3BhbiBjb250ZW50ZWRpdGFibGU9XCJ0cnVlXCI+YCwgdXNlIGBpbm5lclRleHRgLlxyXG4gICAgY29uc3QgdmFsdWUgPSBlLnRhcmdldC52YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgID8gZS50YXJnZXQudmFsdWVcclxuICAgICAgOiBlLnRhcmdldC5pbm5lclRleHQ7XHJcbiAgICBpZiAodmFsdWUudHJpbSgpLmxlbmd0aCA+PSB0aGlzLnR5cGVhaGVhZE1pbkxlbmd0aCkge1xyXG4gICAgICB0aGlzLnR5cGVhaGVhZExvYWRpbmcuZW1pdCh0cnVlKTtcclxuICAgICAgdGhpcy5rZXlVcEV2ZW50RW1pdHRlci5lbWl0KGUudGFyZ2V0LnZhbHVlKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMudHlwZWFoZWFkTG9hZGluZy5lbWl0KGZhbHNlKTtcclxuICAgICAgdGhpcy50eXBlYWhlYWROb1Jlc3VsdHMuZW1pdChmYWxzZSk7XHJcbiAgICAgIHRoaXMuaGlkZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgQEhvc3RMaXN0ZW5lcignZm9jdXMnKVxyXG4gIHB1YmxpYyBvbkZvY3VzKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMudHlwZWFoZWFkTWluTGVuZ3RoID09PSAwKSB7XHJcbiAgICAgIHRoaXMudHlwZWFoZWFkTG9hZGluZy5lbWl0KHRydWUpO1xyXG4gICAgICB0aGlzLmtleVVwRXZlbnRFbWl0dGVyLmVtaXQoJycpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgQEhvc3RMaXN0ZW5lcignYmx1cicpXHJcbiAgcHVibGljIG9uQmx1cigpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLl9jb250YWluZXIgJiYgIXRoaXMuX2NvbnRhaW5lci5pc0ZvY3VzZWQpIHtcclxuICAgICAgdGhpcy50eXBlYWhlYWRPbkJsdXIuZW1pdCh0aGlzLl9jb250YWluZXIuYWN0aXZlKTtcclxuICAgICAgdGhpcy5oaWRlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBASG9zdExpc3RlbmVyKCdrZXlkb3duJywgWyckZXZlbnQnXSlcclxuICBwdWJsaWMgb25LZXlkb3duKGU6IGFueSk6IHZvaWQge1xyXG4gICAgLy8gbm8gY29udGFpbmVyIC0gbm8gcHJvYmxlbXNcclxuICAgIGlmICghdGhpcy5fY29udGFpbmVyKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBpZiBpdGVtcyBpcyB2aXNpYmxlIC0gcHJldmVudCBmb3JtIHN1Ym1pdGlvblxyXG4gICAgaWYgKGUua2V5Q29kZSA9PT0gMTMpIHtcclxuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgY29uc3RydWN0b3IoY29udHJvbDogTmdDb250cm9sLCB2aWV3Q29udGFpbmVyUmVmOiBWaWV3Q29udGFpbmVyUmVmLCBlbGVtZW50OiBFbGVtZW50UmVmLCByZW5kZXJlcjogUmVuZGVyZXIyLCBjaXM6IENvbXBvbmVudExvYWRlckZhY3RvcnkpIHtcclxuICAgIHRoaXMuZWxlbWVudCA9IGVsZW1lbnQ7XHJcbiAgICB0aGlzLm5nQ29udHJvbCA9IGNvbnRyb2w7XHJcbiAgICB0aGlzLnZpZXdDb250YWluZXJSZWYgPSB2aWV3Q29udGFpbmVyUmVmO1xyXG4gICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyO1xyXG4gICAgdGhpcy5fdHlwZWFoZWFkID0gY2lzXHJcbiAgICAgIC5jcmVhdGVMb2FkZXI8VHlwZWFoZWFkQ29udGFpbmVyQ29tcG9uZW50PihlbGVtZW50LCB2aWV3Q29udGFpbmVyUmVmLCByZW5kZXJlcik7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgbmdPbkluaXQoKTogdm9pZCB7XHJcbiAgICB0aGlzLnR5cGVhaGVhZE9wdGlvbnNMaW1pdCA9IHRoaXMudHlwZWFoZWFkT3B0aW9uc0xpbWl0IHx8IDIwO1xyXG4gICAgdGhpcy50eXBlYWhlYWRNaW5MZW5ndGggPSB0aGlzLnR5cGVhaGVhZE1pbkxlbmd0aCA9PT0gdm9pZCAwXHJcbiAgICAgID8gMVxyXG4gICAgICA6IHRoaXMudHlwZWFoZWFkTWluTGVuZ3RoO1xyXG4gICAgdGhpcy50eXBlYWhlYWRXYWl0TXMgPSB0aGlzLnR5cGVhaGVhZFdhaXRNcyB8fCAwO1xyXG5cclxuICAgIC8vIGFzeW5jIHNob3VsZCBiZSBmYWxzZSBpbiBjYXNlIG9mIGFycmF5XHJcbiAgICBpZiAodGhpcy50eXBlYWhlYWRBc3luYyA9PT0gdW5kZWZpbmVkICYmICEodGhpcy50eXBlYWhlYWQgaW5zdGFuY2VvZiBPYnNlcnZhYmxlKSkge1xyXG4gICAgICB0aGlzLnR5cGVhaGVhZEFzeW5jID0gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMudHlwZWFoZWFkIGluc3RhbmNlb2YgT2JzZXJ2YWJsZSkge1xyXG4gICAgICB0aGlzLnR5cGVhaGVhZEFzeW5jID0gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy50eXBlYWhlYWRBc3luYykge1xyXG4gICAgICB0aGlzLmFzeW5jQWN0aW9ucygpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5zeW5jQWN0aW9ucygpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHVibGljIGNoYW5nZU1vZGVsKG1hdGNoOiBUeXBlYWhlYWRNYXRjaCk6IHZvaWQge1xyXG4gICAgY29uc3QgdmFsdWVTdHI6IHN0cmluZyA9IG1hdGNoLnZhbHVlO1xyXG4gICAgdGhpcy5uZ0NvbnRyb2wudmlld1RvTW9kZWxVcGRhdGUodmFsdWVTdHIpO1xyXG4gICAgKHRoaXMubmdDb250cm9sLmNvbnRyb2wgYXMgRm9ybUNvbnRyb2wpLnNldFZhbHVlKHZhbHVlU3RyKTtcclxuICAgIHRoaXMuaGlkZSgpO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIGdldCBtYXRjaGVzKCk6IGFueVtdIHtcclxuICAgIHJldHVybiB0aGlzLl9tYXRjaGVzO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIHNob3coKTogdm9pZCB7XHJcbiAgICB0aGlzLl90eXBlYWhlYWRcclxuICAgICAgLmF0dGFjaChUeXBlYWhlYWRDb250YWluZXJDb21wb25lbnQpXHJcbiAgICAgIC8vIHRvZG86IGFkZCBhcHBlbmQgdG8gYm9keSwgYWZ0ZXIgdXBkYXRpbmcgcG9zaXRpb25pbmcgc2VydmljZVxyXG4gICAgICAudG8odGhpcy5jb250YWluZXIpXHJcbiAgICAgIC5wb3NpdGlvbih7YXR0YWNobWVudDogJ2JvdHRvbSBsZWZ0J30pXHJcbiAgICAgIC5zaG93KHtcclxuICAgICAgICB0eXBlYWhlYWRSZWY6IHRoaXMsXHJcbiAgICAgICAgcGxhY2VtZW50OiB0aGlzLnBsYWNlbWVudCxcclxuICAgICAgICBhbmltYXRpb246IGZhbHNlXHJcbiAgICAgIH0pO1xyXG5cclxuICAgIHRoaXMuX2NvbnRhaW5lciA9IHRoaXMuX3R5cGVhaGVhZC5pbnN0YW5jZTtcclxuICAgIHRoaXMuX2NvbnRhaW5lci5wYXJlbnQgPSB0aGlzO1xyXG4gICAgLy8gVGhpcyBpbXByb3ZlcyB0aGUgc3BlZWQgYXMgaXQgd29uJ3QgaGF2ZSB0byBiZSBkb25lIGZvciBlYWNoIGxpc3QgaXRlbVxyXG4gICAgY29uc3Qgbm9ybWFsaXplZFF1ZXJ5ID0gKHRoaXMudHlwZWFoZWFkTGF0aW5pemVcclxuICAgICAgPyBsYXRpbml6ZSh0aGlzLm5nQ29udHJvbC5jb250cm9sLnZhbHVlKVxyXG4gICAgICA6IHRoaXMubmdDb250cm9sLmNvbnRyb2wudmFsdWUpLnRvU3RyaW5nKClcclxuICAgICAgLnRvTG93ZXJDYXNlKCk7XHJcbiAgICB0aGlzLl9jb250YWluZXIucXVlcnkgPSB0aGlzLnR5cGVhaGVhZFNpbmdsZVdvcmRzXHJcbiAgICAgID8gdG9rZW5pemUobm9ybWFsaXplZFF1ZXJ5LCB0aGlzLnR5cGVhaGVhZFdvcmREZWxpbWl0ZXJzLCB0aGlzLnR5cGVhaGVhZFBocmFzZURlbGltaXRlcnMpXHJcbiAgICAgIDogbm9ybWFsaXplZFF1ZXJ5O1xyXG4gICAgdGhpcy5fY29udGFpbmVyLm1hdGNoZXMgPSB0aGlzLl9tYXRjaGVzO1xyXG4gICAgdGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBoaWRlKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuX3R5cGVhaGVhZC5pc1Nob3duKSB7XHJcbiAgICAgIHRoaXMuX3R5cGVhaGVhZC5oaWRlKCk7XHJcbiAgICAgIHRoaXMuX2NvbnRhaW5lciA9IG51bGw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgbmdPbkRlc3Ryb3koKTogYW55IHtcclxuICAgIHRoaXMuX3R5cGVhaGVhZC5kaXNwb3NlKCk7XHJcbiAgfVxyXG5cclxuICBwcm90ZWN0ZWQgYXN5bmNBY3Rpb25zKCk6IHZvaWQge1xyXG4gICAgdGhpcy5rZXlVcEV2ZW50RW1pdHRlci5waXBlKFxyXG4gICAgICBkZWJvdW5jZVRpbWUodGhpcy50eXBlYWhlYWRXYWl0TXMpLFxyXG4gICAgICBtZXJnZU1hcCgoKSA9PiB0aGlzLnR5cGVhaGVhZClcclxuICAgICkuc3Vic2NyaWJlKFxyXG4gICAgICAgIChtYXRjaGVzOiBhbnlbXSkgPT4ge1xyXG4gICAgICAgICAgdGhpcy5maW5hbGl6ZUFzeW5jQ2FsbChtYXRjaGVzKTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIChlcnI6IGFueSkgPT4ge1xyXG4gICAgICAgICAgY29uc29sZS5lcnJvcihlcnIpO1xyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICB9XHJcblxyXG4gIHByb3RlY3RlZCBzeW5jQWN0aW9ucygpOiB2b2lkIHtcclxuICAgIHRoaXMua2V5VXBFdmVudEVtaXR0ZXIucGlwZShcclxuICAgICAgZGVib3VuY2VUaW1lKHRoaXMudHlwZWFoZWFkV2FpdE1zKSxcclxuICAgICAgbWVyZ2VNYXAoKHZhbHVlOiBzdHJpbmcpID0+IHtcclxuICAgICAgICBjb25zdCBub3JtYWxpemVkUXVlcnkgPSB0aGlzLm5vcm1hbGl6ZVF1ZXJ5KHZhbHVlKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIGZyb20odGhpcy50eXBlYWhlYWQpLnBpcGUoXHJcbiAgICAgICAgICBmaWx0ZXIoKG9wdGlvbjogYW55KSA9PiB7XHJcbiAgICAgICAgICAgIHJldHVybiBvcHRpb24gJiYgdGhpcy50ZXN0TWF0Y2godGhpcy5ub3JtYWxpemVPcHRpb24ob3B0aW9uKSwgbm9ybWFsaXplZFF1ZXJ5KTtcclxuICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgdG9BcnJheSgpXHJcbiAgICAgICAgKTtcclxuICAgICAgfSkpXHJcbiAgICAgIC5zdWJzY3JpYmUoXHJcbiAgICAgICAgKG1hdGNoZXM6IGFueVtdKSA9PiB7XHJcbiAgICAgICAgICB0aGlzLmZpbmFsaXplQXN5bmNDYWxsKG1hdGNoZXMpO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgKGVycjogYW55KSA9PiB7XHJcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGVycik7XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIG5vcm1hbGl6ZU9wdGlvbihvcHRpb246IGFueSk6IGFueSB7XHJcbiAgICBjb25zdCBvcHRpb25WYWx1ZTogc3RyaW5nID0gZ2V0VmFsdWVGcm9tT2JqZWN0KG9wdGlvbiwgdGhpcy50eXBlYWhlYWRPcHRpb25GaWVsZCk7XHJcbiAgICBjb25zdCBub3JtYWxpemVkT3B0aW9uID0gdGhpcy50eXBlYWhlYWRMYXRpbml6ZVxyXG4gICAgICA/IGxhdGluaXplKG9wdGlvblZhbHVlKVxyXG4gICAgICA6IG9wdGlvblZhbHVlO1xyXG5cclxuICAgIHJldHVybiBub3JtYWxpemVkT3B0aW9uLnRvTG93ZXJDYXNlKCk7XHJcbiAgfVxyXG5cclxuICBwcm90ZWN0ZWQgbm9ybWFsaXplUXVlcnkodmFsdWU6IHN0cmluZyk6IGFueSB7XHJcbiAgICAvLyBJZiBzaW5nbGVXb3JkcywgYnJlYWsgbW9kZWwgaGVyZSB0byBub3QgYmUgZG9pbmcgZXh0cmEgd29yayBvbiBlYWNoXHJcbiAgICAvLyBpdGVyYXRpb25cclxuICAgIGxldCBub3JtYWxpemVkUXVlcnk6IGFueSA9XHJcbiAgICAgICh0aGlzLnR5cGVhaGVhZExhdGluaXplID8gbGF0aW5pemUodmFsdWUpIDogdmFsdWUpXHJcbiAgICAgICAgLnRvU3RyaW5nKClcclxuICAgICAgICAudG9Mb3dlckNhc2UoKTtcclxuICAgIG5vcm1hbGl6ZWRRdWVyeSA9IHRoaXMudHlwZWFoZWFkU2luZ2xlV29yZHNcclxuICAgICAgPyB0b2tlbml6ZShub3JtYWxpemVkUXVlcnksIHRoaXMudHlwZWFoZWFkV29yZERlbGltaXRlcnMsIHRoaXMudHlwZWFoZWFkUGhyYXNlRGVsaW1pdGVycylcclxuICAgICAgOiBub3JtYWxpemVkUXVlcnk7XHJcblxyXG4gICAgcmV0dXJuIG5vcm1hbGl6ZWRRdWVyeTtcclxuICB9XHJcblxyXG4gIHByb3RlY3RlZCB0ZXN0TWF0Y2gobWF0Y2g6IHN0cmluZywgdGVzdDogYW55KTogYm9vbGVhbiB7XHJcbiAgICBsZXQgc3BhY2VMZW5ndGg6IG51bWJlcjtcclxuXHJcbiAgICBpZiAodHlwZW9mIHRlc3QgPT09ICdvYmplY3QnKSB7XHJcbiAgICAgIHNwYWNlTGVuZ3RoID0gdGVzdC5sZW5ndGg7XHJcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc3BhY2VMZW5ndGg7IGkgKz0gMSkge1xyXG4gICAgICAgIGlmICh0ZXN0W2ldLmxlbmd0aCA+IDAgJiYgbWF0Y2guaW5kZXhPZih0ZXN0W2ldKSA8IDApIHtcclxuICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gbWF0Y2guaW5kZXhPZih0ZXN0KSA+PSAwO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIGZpbmFsaXplQXN5bmNDYWxsKG1hdGNoZXM6IGFueVtdKTogdm9pZCB7XHJcbiAgICB0aGlzLnByZXBhcmVNYXRjaGVzKG1hdGNoZXMpO1xyXG5cclxuICAgIHRoaXMudHlwZWFoZWFkTG9hZGluZy5lbWl0KGZhbHNlKTtcclxuICAgIHRoaXMudHlwZWFoZWFkTm9SZXN1bHRzLmVtaXQoIXRoaXMuaGFzTWF0Y2hlcygpKTtcclxuXHJcbiAgICBpZiAoIXRoaXMuaGFzTWF0Y2hlcygpKSB7XHJcbiAgICAgIHRoaXMuaGlkZSgpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMuX2NvbnRhaW5lcikge1xyXG4gICAgICAvLyBUaGlzIGltcHJvdmVzIHRoZSBzcGVlZCBhcyBpdCB3b24ndCBoYXZlIHRvIGJlIGRvbmUgZm9yIGVhY2ggbGlzdCBpdGVtXHJcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWRRdWVyeSA9ICh0aGlzLnR5cGVhaGVhZExhdGluaXplXHJcbiAgICAgICAgPyBsYXRpbml6ZSh0aGlzLm5nQ29udHJvbC5jb250cm9sLnZhbHVlKVxyXG4gICAgICAgIDogdGhpcy5uZ0NvbnRyb2wuY29udHJvbC52YWx1ZSkudG9TdHJpbmcoKVxyXG4gICAgICAgIC50b0xvd2VyQ2FzZSgpO1xyXG4gICAgICB0aGlzLl9jb250YWluZXIucXVlcnkgPSB0aGlzLnR5cGVhaGVhZFNpbmdsZVdvcmRzXHJcbiAgICAgICAgPyB0b2tlbml6ZShub3JtYWxpemVkUXVlcnksIHRoaXMudHlwZWFoZWFkV29yZERlbGltaXRlcnMsIHRoaXMudHlwZWFoZWFkUGhyYXNlRGVsaW1pdGVycylcclxuICAgICAgICA6IG5vcm1hbGl6ZWRRdWVyeTtcclxuICAgICAgdGhpcy5fY29udGFpbmVyLm1hdGNoZXMgPSB0aGlzLl9tYXRjaGVzO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5zaG93KCk7XHJcbiAgICB