@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
JavaScript
/**
* @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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZWFoZWFkLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0BoeHVpL2FuZ3VsYXIvIiwic291cmNlcyI6WyJsaWIvdHlwZWFoZWFkL3R5cGVhaGVhZC5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUN4RCxNQUFNLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxnQkFBZ0IsRUFDakQsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFlLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3hELE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzlFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFM0UsT0FBTyxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDeEMsT0FBTyxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw4Q0FBOEMsQ0FBQztBQUl0RixNQUFNOzs7Ozs7OztnQkFpSmUsT0FBa0IsRUFBRSxnQkFBa0MsRUFBRSxPQUFtQixFQUFFLFFBQW1CLEVBQUUsR0FBMkI7Ozs7a0NBN0luRyxLQUFLLENBQUM7Ozs7OEJBVVQsS0FBSyxDQUFDOzs7O2lDQUVaLElBQUk7Ozs7b0NBRUQsSUFBSTs7Ozt1Q0FFRCxHQUFHOzs7O3lDQUVELEtBQUs7Ozs7Z0NBT1UsSUFBSSxZQUFZLEVBQUU7Ozs7a0NBRWhCLElBQUksWUFBWSxFQUFFOzs7O2lDQUVaLElBQUksWUFBWSxFQUFFOzs7OytCQUUvQixJQUFJLFlBQVksRUFBRTs0Q0F1QmxDLEtBQUs7aUNBRU0sSUFBSSxZQUFZLEVBQUU7eUJBRTdDLGFBQWE7UUFvRmpDLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDO1FBQ3pCLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxnQkFBZ0IsQ0FBQztRQUN6QyxJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQztRQUN6QixJQUFJLENBQUMsVUFBVSxHQUFHLEdBQUc7YUFDbEIsWUFBWSxDQUE4QixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsUUFBUSxDQUFDLENBQUM7Ozs7OztJQTlFN0UsUUFBUSxDQUFDLENBQU07UUFDcEIsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7O1lBRXBCLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDckIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUNaLE1BQU0sQ0FBQzthQUNSOztZQUdELEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDckIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxlQUFlLEVBQUUsQ0FBQztnQkFDbEMsTUFBTSxDQUFDO2FBQ1I7O1lBR0QsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDO2dCQUNyQixJQUFJLENBQUMsVUFBVSxDQUFDLGVBQWUsRUFBRSxDQUFDO2dCQUNsQyxNQUFNLENBQUM7YUFDUjs7WUFHRCxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7Z0JBQ3JCLElBQUksQ0FBQyxVQUFVLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztnQkFDcEMsTUFBTSxDQUFDO2FBQ1I7U0FDRjs7O1FBSUQsdUJBQU0sS0FBSyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxLQUFLLFNBQVM7WUFDeEMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSztZQUNoQixDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUM7UUFDdkIsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDLE1BQU0sSUFBSSxJQUFJLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDO1lBQ25ELElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDakMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1NBQzdDO1FBQUMsSUFBSSxDQUFDLENBQUM7WUFDTixJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ2xDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDcEMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1NBQ2I7Ozs7O0lBSUksT0FBTztRQUNaLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ2xDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDakMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztTQUNqQzs7Ozs7SUFJSSxNQUFNO1FBQ1gsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQztZQUNsRCxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ2xELElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztTQUNiOzs7Ozs7SUFJSSxTQUFTLENBQUMsQ0FBTTs7UUFFckIsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztZQUNyQixNQUFNLENBQUM7U0FDUjs7UUFHRCxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDckIsQ0FBQyxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ25CLE1BQU0sQ0FBQztTQUNSOzs7OztJQVlJLFFBQVE7UUFDYixJQUFJLENBQUMscUJBQXFCLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixJQUFJLEVBQUUsQ0FBQztRQUM5RCxJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixLQUFLLEtBQUssQ0FBQztZQUMxRCxDQUFDLENBQUMsQ0FBQztZQUNILENBQUMsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUM7UUFDNUIsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUMsZUFBZSxJQUFJLENBQUMsQ0FBQzs7UUFHakQsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLGNBQWMsS0FBSyxTQUFTLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLFlBQVksVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ2pGLElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDO1NBQzdCO1FBRUQsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsWUFBWSxVQUFVLENBQUMsQ0FBQyxDQUFDO1lBQ3pDLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDO1NBQzVCO1FBRUQsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUM7WUFDeEIsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1NBQ3JCO1FBQUMsSUFBSSxDQUFDLENBQUM7WUFDTixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7U0FDcEI7Ozs7OztJQUdJLFdBQVcsQ0FBQyxLQUFxQjtRQUN0Qyx1QkFBTSxRQUFRLEdBQVcsS0FBSyxDQUFDLEtBQUssQ0FBQztRQUNyQyxJQUFJLENBQUMsU0FBUyxDQUFDLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQzNDLG1CQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBc0IsRUFBQyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUMzRCxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7Ozs7O1FBR0gsT0FBTztRQUNoQixNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQzs7Ozs7SUFHaEIsSUFBSTtRQUNULElBQUksQ0FBQyxVQUFVO2FBQ1osTUFBTSxDQUFDLDJCQUEyQixDQUFDO2FBRW5DLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDO2FBQ2xCLFFBQVEsQ0FBQyxFQUFDLFVBQVUsRUFBRSxhQUFhLEVBQUMsQ0FBQzthQUNyQyxJQUFJLENBQUM7WUFDSixZQUFZLEVBQUUsSUFBSTtZQUNsQixTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7WUFDekIsU0FBUyxFQUFFLEtBQUs7U0FDakIsQ0FBQyxDQUFDO1FBRUwsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQztRQUMzQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUM7O1FBRTlCLHVCQUFNLGVBQWUsR0FBRyxDQUFDLElBQUksQ0FBQyxpQkFBaUI7WUFDN0MsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7WUFDeEMsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLFFBQVEsRUFBRTthQUN6QyxXQUFXLEVBQUUsQ0FBQztRQUNqQixJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsb0JBQW9CO1lBQy9DLENBQUMsQ0FBQyxRQUFRLENBQUMsZUFBZSxFQUFFLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxJQUFJLENBQUMseUJBQXlCLENBQUM7WUFDekYsQ0FBQyxDQUFDLGVBQWUsQ0FBQztRQUNwQixJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDO1FBQ3hDLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxDQUFDOzs7OztJQUc5QixJQUFJO1FBQ1QsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1lBQzVCLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDdkIsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUM7U0FDeEI7Ozs7O0lBR0ksV0FBVztRQUNoQixJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDOzs7OztJQUdsQixZQUFZO1FBQ3BCLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQ3pCLFlBQVksQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLEVBQ2xDLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQy9CLENBQUMsU0FBUyxDQUNQLENBQUMsT0FBYyxFQUFFLEVBQUU7WUFDakIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1NBQ2pDLEVBQ0QsQ0FBQyxHQUFRLEVBQUUsRUFBRTtZQUNYLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7U0FDcEIsQ0FDRixDQUFDO0tBQ0w7Ozs7SUFFUyxXQUFXO1FBQ25CLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQ3pCLFlBQVksQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLEVBQ2xDLFFBQVEsQ0FBQyxDQUFDLEtBQWEsRUFBRSxFQUFFO1lBQ3pCLHVCQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBRW5ELE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLElBQUksQ0FDOUIsTUFBTSxDQUFDLENBQUMsTUFBVyxFQUFFLEVBQUU7Z0JBQ3JCLE1BQU0sQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxFQUFFLGVBQWUsQ0FBQyxDQUFDO2FBQ2hGLENBQUMsRUFDRixPQUFPLEVBQUUsQ0FDVixDQUFDO1NBQ0gsQ0FBQyxDQUFDO2FBQ0YsU0FBUyxDQUNSLENBQUMsT0FBYyxFQUFFLEVBQUU7WUFDakIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1NBQ2pDLEVBQ0QsQ0FBQyxHQUFRLEVBQUUsRUFBRTtZQUNYLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7U0FDcEIsQ0FDRixDQUFDO0tBQ0w7Ozs7O0lBRVMsZUFBZSxDQUFDLE1BQVc7UUFDbkMsdUJBQU0sV0FBVyxHQUFXLGtCQUFrQixDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUNsRix1QkFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsaUJBQWlCO1lBQzdDLENBQUMsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDO1lBQ3ZCLENBQUMsQ0FBQyxXQUFXLENBQUM7UUFFaEIsTUFBTSxDQUFDLGdCQUFnQixDQUFDLFdBQVcsRUFBRSxDQUFDO0tBQ3ZDOzs7OztJQUVTLGNBQWMsQ0FBQyxLQUFhOzs7UUFHcEMscUJBQUksZUFBZSxHQUNqQixDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7YUFDL0MsUUFBUSxFQUFFO2FBQ1YsV0FBVyxFQUFFLENBQUM7UUFDbkIsZUFBZSxHQUFHLElBQUksQ0FBQyxvQkFBb0I7WUFDekMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxlQUFlLEVBQUUsSUFBSSxDQUFDLHVCQUF1QixFQUFFLElBQUksQ0FBQyx5QkFBeUIsQ0FBQztZQUN6RixDQUFDLENBQUMsZUFBZSxDQUFDO1FBRXBCLE1BQU0sQ0FBQyxlQUFlLENBQUM7S0FDeEI7Ozs7OztJQUVTLFNBQVMsQ0FBQyxLQUFhLEVBQUUsSUFBUztRQUMxQyxxQkFBSSxXQUFtQixDQUFDO1FBRXhCLEVBQUUsQ0FBQyxDQUFDLE9BQU8sSUFBSSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUM7WUFDN0IsV0FBVyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUM7WUFDMUIsR0FBRyxDQUFDLENBQUMscUJBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsV0FBVyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztnQkFDeEMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUNyRCxNQUFNLENBQUMsS0FBSyxDQUFDO2lCQUNkO2FBQ0Y7WUFDRCxNQUFNLENBQUMsSUFBSSxDQUFDO1NBQ2I7UUFBQyxJQUFJLENBQUMsQ0FBQztZQUNOLE1BQU0sQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUNqQztLQUNGOzs7OztJQUVTLGlCQUFpQixDQUFDLE9BQWM7UUFDeEMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUU3QixJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2xDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUVqRCxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDdkIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ1osTUFBTSxDQUFDO1NBQ1I7UUFFRCxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQzs7WUFFcEIsdUJBQU0sZUFBZSxHQUFHLENBQUMsSUFBSSxDQUFDLGlCQUFpQjtnQkFDN0MsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7Z0JBQ3hDLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxRQUFRLEVBQUU7aUJBQ3pDLFdBQVcsRUFBRSxDQUFDO1lBQ2pCLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxvQkFBb0I7Z0JBQy9DLENBQUMsQ0FBQyxRQUFRLENBQUMsZUFBZSxFQUFFLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxJQUFJLENBQUMseUJBQXlCLENBQUM7Z0JBQ3pGLENBQUMsQ0FBQyxlQUFlLENBQUM7WUFDcEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQztTQUN6QztRQUFDLElBQUksQ0FBQyxDQUFDO1lBQ04sSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1NBQ2I7S0FDRjs7Ozs7SUFFUyxjQUFjLENBQUMsT0FBYztRQUNyQyx1QkFBTSxPQUFPLEdBQVUsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLHFCQUFxQixDQUFDLENBQUM7UUFFcEUsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUMsQ0FBQztZQUM3QixxQkFBSSxPQUFPLEdBQXFCLEVBQUUsQ0FBQzs7WUFHbkMsdUJBQU0sTUFBTSxHQUFHLE9BQU87aUJBQ25CLEdBQUcsQ0FBQyxDQUFDLE1BQVcsRUFBRSxFQUFFLENBQUMsa0JBQWtCLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO2lCQUMxRSxNQUFNLENBQUMsQ0FBQyxDQUFTLEVBQUUsQ0FBUyxFQUFFLENBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztZQUVsRSxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBYSxFQUFFLEVBQUU7O2dCQUUvQixPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksY0FBYyxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQzs7Z0JBR3JELE9BQU8sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLE9BQU87cUJBQzdCLE1BQU0sQ0FBQyxDQUFDLE1BQVcsRUFBRSxFQUFFLENBQUMsa0JBQWtCLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLEtBQUssQ0FBQztxQkFDdkYsR0FBRyxDQUFDLENBQUMsTUFBVyxFQUFFLEVBQUUsQ0FBQyxJQUFJLGNBQWMsQ0FBQyxNQUFNLEVBQUUsa0JBQWtCLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2FBQzdHLENBQUMsQ0FBQztZQUVILElBQUksQ0FBQyxRQUFRLEdBQUcsT0FBTyxDQUFDO1NBQ3pCO1FBQUMsSUFBSSxDQUFDLENBQUM7WUFDTixJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFXLEVBQUUsRUFBRSxDQUFDLElBQUksY0FBYyxDQUFDLE1BQU0sRUFBRSxrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQ2pJO0tBQ0Y7Ozs7SUFFUyxVQUFVO1FBQ2xCLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7S0FDakM7OztZQXJXRixTQUFTLFNBQUMsRUFBQyxRQUFRLEVBQUUsYUFBYSxFQUFFLFFBQVEsRUFBRSxjQUFjLEVBQUM7Ozs7WUFWeEMsU0FBUztZQUZHLGdCQUFnQjtZQURyQyxVQUFVO1lBQ2IsU0FBUztZQVNWLHNCQUFzQjs7OzBCQU01QixLQUFLO21DQUVMLEtBQUs7Z0NBRUwsS0FBSztzQ0FFTCxLQUFLO3FDQUVMLEtBQUs7b0NBRUwsS0FBSzsrQkFFTCxLQUFLO2tDQUVMLEtBQUs7cUNBRUwsS0FBSzt3Q0FFTCxLQUFLOzBDQUVMLEtBQUs7c0NBRUwsS0FBSztvQ0FFTCxLQUFLO2lDQUdMLE1BQU07bUNBRU4sTUFBTTtrQ0FFTixNQUFNO2dDQUVOLE1BQU07MEJBTU4sS0FBSzt5QkErQkwsWUFBWSxTQUFDLE9BQU8sRUFBRSxDQUFDLFFBQVEsQ0FBQzt3QkEyQ2hDLFlBQVksU0FBQyxPQUFPO3VCQVFwQixZQUFZLFNBQUMsTUFBTTswQkFRbkIsWUFBWSxTQUFDLFNBQVMsRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgRGlyZWN0aXZlLCBFbGVtZW50UmVmLCBFdmVudEVtaXR0ZXIsIEhvc3RMaXN0ZW5lciwgSW5wdXQsIE9uRGVzdHJveSwgT25Jbml0LFxyXG4gIE91dHB1dCwgUmVuZGVyZXIyLCBUZW1wbGF0ZVJlZiwgVmlld0NvbnRhaW5lclJlZlxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBGb3JtQ29udHJvbCwgTmdDb250cm9sIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xyXG5pbXBvcnQgeyBUeXBlYWhlYWRDb250YWluZXJDb21wb25lbnQgfSBmcm9tICcuL3R5cGVhaGVhZC1jb250YWluZXIuY29tcG9uZW50JztcclxuaW1wb3J0IHsgZ2V0VmFsdWVGcm9tT2JqZWN0LCBsYXRpbml6ZSwgdG9rZW5pemUgfSBmcm9tICcuL3R5cGVhaGVhZC11dGlscyc7XHJcblxyXG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBmcm9tIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IGRlYm91bmNlVGltZSwgbWVyZ2VNYXAsIGZpbHRlciwgdG9BcnJheSB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgVHlwZWFoZWFkTWF0Y2ggfSBmcm9tICcuL3R5cGVhaGVhZC1tYXRjaC5jbGFzcyc7XHJcbmltcG9ydCB7IENvbXBvbmVudExvYWRlckZhY3RvcnkgfSBmcm9tICcuLi9jb21wb25lbnQtbG9hZGVyL2NvbXBvbmVudC1sb2FkZXIuZmFjdG9yeSc7XHJcbmltcG9ydCB7IENvbXBvbmVudExvYWRlciB9IGZyb20gJy4uL2NvbXBvbmVudC1sb2FkZXIvY29tcG9uZW50LWxvYWRlci5jbGFzcyc7XHJcblxyXG5ARGlyZWN0aXZlKHtzZWxlY3RvcjogJ1t0eXBlYWhlYWRdJywgZXhwb3J0QXM6ICdoeC10eXBlYWhlYWQnfSlcclxuZXhwb3J0IGNsYXNzIFR5cGVhaGVhZERpcmVjdGl2ZSBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcclxuICAvKiogb3B0aW9ucyBzb3VyY2UsIGNhbiBiZSBBcnJheSBvZiBzdHJpbmdzLCBvYmplY3RzIG9yIGFuIE9ic2VydmFibGUgZm9yIGV4dGVybmFsIG1hdGNoaW5nIHByb2Nlc3MgKi9cclxuICBASW5wdXQoKSBwdWJsaWMgdHlwZWFoZWFkOiBhbnk7XHJcbiAgLyoqIG1pbmltYWwgbm8gb2YgY2hhcmFjdGVycyB0aGF0IG5lZWRzIHRvIGJlIGVudGVyZWQgYmVmb3JlIHR5cGVhaGVhZCBraWNrcy1pbi4gV2hlbiBzZXQgdG8gMCwgdHlwZWFoZWFkIHNob3dzIG9uIGZvY3VzIHdpdGggZnVsbCBsaXN0IG9mIG9wdGlvbnMgKGxpbWl0ZWQgYXMgbm9ybWFsIGJ5IHR5cGVhaGVhZE9wdGlvbnNMaW1pdCkgKi9cclxuICBASW5wdXQoKSBwdWJsaWMgdHlwZWFoZWFkTWluTGVuZ3RoOiBudW1iZXIgPSB2b2lkIDA7XHJcbiAgLyoqIG1pbmltYWwgd2FpdCB0aW1lIGFmdGVyIGxhc3QgY2hhcmFjdGVyIHR5cGVkIGJlZm9yZSB0eXBlYWhlYWQga2lja3MtaW4gKi9cclxuICBASW5wdXQoKSBwdWJsaWMgdHlwZWFoZWFkV2FpdE1zOiBudW1iZXI7XHJcbiAgLyoqIG1heGltdW0gbGVuZ3RoIG9mIG9wdGlvbnMgaXRlbXMgbGlzdCAqL1xyXG4gIEBJbnB1dCgpIHB1YmxpYyB0eXBlYWhlYWRPcHRpb25zTGltaXQ6IG51bWJlcjtcclxuICAvKiogd2hlbiBvcHRpb25zIHNvdXJjZSBpcyBhbiBhcnJheSBvZiBvYmplY3RzLCB0aGUgbmFtZSBvZiBmaWVsZCB0aGF0IGNvbnRhaW5zIHRoZSBvcHRpb25zIHZhbHVlLCB3ZSB1c2UgYXJyYXkgaXRlbSBhcyBvcHRpb24gaW4gY2FzZSBvZiB0aGlzIGZpZWxkIGlzIG1pc3NpbmcuIFN1cHBvcnRzIG5lc3RlZCBwcm9wZXJ0aWVzIGFuZCBtZXRob2RzLiAqL1xyXG4gIEBJbnB1dCgpIHB1YmxpYyB0eXBlYWhlYWRPcHRpb25GaWVsZDogc3RyaW5nO1xyXG4gIC8qKiB3aGVuIG9wdGlvbnMgc291cmNlIGlzIGFuIGFycmF5IG9mIG9iamVjdHMsIHRoZSBuYW1lIG9mIGZpZWxkIHRoYXQgY29udGFpbnMgdGhlIGdyb3VwIHZhbHVlLCBtYXRjaGVzIGFyZSBncm91cGVkIGJ5IHRoaXMgZmllbGQgd2hlbiBzZXQuICovXHJcbiAgQElucHV0KCkgcHVibGljIHR5cGVhaGVhZEdyb3VwRmllbGQ6IHN0cmluZztcclxuICAvKiogc2hvdWxkIGJlIHVzZWQgb25seSBpbiBjYXNlIG9mIHR5cGVhaGVhZCBhdHRyaWJ1dGUgaXMgYXJyYXkuIElmIHRydWUgLSBsb2FkaW5nIG9mIG9wdGlvbnMgd2lsbCBiZSBhc3luYywgb3RoZXJ3aXNlIC0gc3luYy4gdHJ1ZSBtYWtlIHNlbnNlIGlmIG9wdGlvbnMgYXJyYXkgaXMgbGFyZ2UuICovXHJcbiAgQElucHV0KCkgcHVibGljIHR5cGVhaGVhZEFzeW5jOiBib29sZWFuID0gdm9pZCAwO1xyXG4gIC8qKiBtYXRjaCBsYXRpbiBzeW1ib2xzLiBJZiB0cnVlIHRoZSB3b3JkIHPDunBlciB3b3VsZCBtYXRjaCBzdXBlciBhbmQgdmljZSB2ZXJzYS4gKi9cclxuICBASW5wdXQoKSBwdWJsaWMgdHlwZWFoZWFkTGF0aW5pemUgPSB0cnVlO1xyXG4gIC8qKiBicmVhayB3b3JkcyB3aXRoIHNwYWNlcy4gSWYgdHJ1ZSB0aGUgdGV4dCBcImV4YWN0IHBocmFzZVwiIGhlcmUgbWF0Y2ggd291bGQgbWF0Y2ggd2l0aCBtYXRjaCBleGFjdCBwaHJhc2UgaGVyZSBidXQgbm90IHdpdGggcGhyYXNlIGhlcmUgZXhhY3QgbWF0Y2ggKGtpbmQgb2YgXCJnb29nbGUgc3R5bGVcIikuICovXHJcbiAgQElucHV0KCkgcHVibGljIHR5cGVhaGVhZFNpbmdsZVdvcmRzID0gdHJ1ZTtcclxuICAvKiogc2hvdWxkIGJlIHVzZWQgb25seSBpbiBjYXNlIHR5cGVhaGVhZFNpbmdsZVdvcmRzIGF0dHJpYnV0ZSBpcyB0cnVlLiBTZXRzIHRoZSB3b3JkIGRlbGltaXRlciB0byBicmVhayB3b3Jkcy4gRGVmYXVsdHMgdG8gc3BhY2UuICovXHJcbiAgQElucHV0KCkgcHVibGljIHR5cGVhaGVhZFdvcmREZWxpbWl0ZXJzID0gJyAnO1xyXG4gIC8qKiBzaG91bGQgYmUgdXNlZCBvbmx5IGluIGNhc2UgdHlwZWFoZWFkU2luZ2xlV29yZHMgYXR0cmlidXRlIGlzIHRydWUuIFNldHMgdGhlIHdvcmQgZGVsaW1pdGVyIHRvIG1hdGNoIGV4YWN0IHBocmFzZS4gRGVmYXVsdHMgdG8gc2ltcGxlIGFuZCBkb3VibGUgcXVvdGVzLiAqL1xyXG4gIEBJbnB1dCgpIHB1YmxpYyB0eXBlYWhlYWRQaHJhc2VEZWxpbWl0ZXJzID0gJ1xcJ1wiJztcclxuICAvKiogdXNlZCB0byBzcGVjaWZ5IGEgY3VzdG9tIGl0ZW0gdGVtcGxhdGUuIFRlbXBsYXRlIHZhcmlhYmxlcyBleHBvc2VkIGFyZSBjYWxsZWQgaXRlbSBhbmQgaW5kZXg7ICovXHJcbiAgQElucHV0KCkgcHVibGljIHR5cGVhaGVhZEl0ZW1UZW1wbGF0ZTogVGVtcGxhdGVSZWY8YW55PjtcclxuICAvKiogdXNlZCB0byBzcGVjaWZ5IGEgY3VzdG9tIG9wdGlvbnMgbGlzdCB0ZW1wbGF0ZS4gVGVtcGxhdGUgdmFyaWFibGVzOiBtYXRjaGVzLCBpdGVtVGVtcGxhdGUsIHF1ZXJ5ICovXHJcbiAgQElucHV0KCkgcHVibGljIG9wdGlvbnNMaXN0VGVtcGxhdGU6IFRlbXBsYXRlUmVmPGFueT47XHJcblxyXG4gIC8qKiBmaXJlZCB3aGVuICdidXN5JyBzdGF0ZSBvZiB0aGlzIGNvbXBvbmVudCB3YXMgY2hhbmdlZCwgZmlyZWQgb24gYXN5bmMgbW9kZSBvbmx5LCByZXR1cm5zIGJvb2xlYW4gKi9cclxuICBAT3V0cHV0KCkgcHVibGljIHR5cGVhaGVhZExvYWRpbmc6IEV2ZW50RW1pdHRlcjxib29sZWFuPiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcclxuICAvKiogZmlyZWQgb24gZXZlcnkga2V5IGV2ZW50IGFuZCByZXR1cm5zIHRydWUgaW4gY2FzZSBvZiBtYXRjaGVzIGFyZSBub3QgZGV0ZWN0ZWQgKi9cclxuICBAT3V0cHV0KCkgcHVibGljIHR5cGVhaGVhZE5vUmVzdWx0czogRXZlbnRFbWl0dGVyPGJvb2xlYW4+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xyXG4gIC8qKiBmaXJlZCB3aGVuIG9wdGlvbiB3YXMgc2VsZWN0ZWQsIHJldHVybiBvYmplY3Qgd2l0aCBkYXRhIG9mIHRoaXMgb3B0aW9uICovXHJcbiAgQE91dHB1dCgpIHB1YmxpYyB0eXBlYWhlYWRPblNlbGVjdDogRXZlbnRFbWl0dGVyPFR5cGVhaGVhZE1hdGNoPiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcclxuICAvKiogZmlyZWQgd2hlbiBibHVyIGV2ZW50IG9jY3VycmVzLiByZXR1cm5zIHRoZSBhY3RpdmUgaXRlbSAqL1xyXG4gIEBPdXRwdXQoKSBwdWJsaWMgdHlwZWFoZWFkT25CbHVyOiBFdmVudEVtaXR0ZXI8YW55PiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQSBzZWxlY3RvciBzcGVjaWZ5aW5nIHRoZSBlbGVtZW50IHRoZSB0eXBlYWhlYWQgc2hvdWxkIGJlIGFwcGVuZGVkIHRvLlxyXG4gICAqIEN1cnJlbnRseSBvbmx5IHN1cHBvcnRzIFwiYm9keVwiLlxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIHB1YmxpYyBjb250YWluZXI6IHN0cmluZztcclxuXHJcbiAgLy8gbm90IHlldCBpbXBsZW1lbnRlZFxyXG4gIC8qKiBpZiBmYWxzZSByZXN0cmljdCBtb2RlbCB2YWx1ZXMgdG8gdGhlIG9uZXMgc2VsZWN0ZWQgZnJvbSB0aGUgcG9wdXAgb25seSB3aWxsIGJlIHByb3ZpZGVkICovXHJcbiAgLy8gQElucHV0KCkgcHJvdGVjdGVkIHR5cGVhaGVhZEVkaXRhYmxlOmJvb2xlYW47XHJcbiAgLyoqIGlmIGZhbHNlIHRoZSBmaXJzdCBtYXRjaCBhdXRvbWF0aWNhbGx5IHdpbGwgbm90IGJlIGZvY3VzZWQgYXMgeW91IHR5cGUgKi9cclxuICAvLyBASW5wdXQoKSBwcm90ZWN0ZWQgdHlwZWFoZWFkRm9jdXNGaXJzdDpib29sZWFuO1xyXG4gIC8qKiBmb3JtYXQgdGhlIG5nLW1vZGVsIHJlc3VsdCBhZnRlciBzZWxlY3Rpb24gKi9cclxuICAvLyBASW5wdXQoKSBwcm90ZWN0ZWQgdHlwZWFoZWFkSW5wdXRGb3JtYXR0ZXI6YW55O1xyXG4gIC8qKiBpZiB0cnVlIGF1dG9tYXRpY2FsbHkgc2VsZWN0IGFuIGl0ZW0gd2hlbiB0aGVyZSBpcyBvbmUgb3B0aW9uIHRoYXQgZXhhY3RseSBtYXRjaGVzIHRoZSB1c2VyIGlucHV0ICovXHJcbiAgLy8gQElucHV0KCkgcHJvdGVjdGVkIHR5cGVhaGVhZFNlbGVjdE9uRXhhY3Q6Ym9vbGVhbjtcclxuICAvKiogIGlmIHRydWUgc2VsZWN0IHRoZSBjdXJyZW50bHkgaGlnaGxpZ2h0ZWQgbWF0Y2ggb24gYmx1ciAqL1xyXG4gIC8vIEBJbnB1dCgpIHByb3RlY3RlZCB0eXBlYWhlYWRTZWxlY3RPbkJsdXI6Ym9vbGVhbjtcclxuICAvKiogIGlmIGZhbHNlIGRvbid0IGZvY3VzIHRoZSBpbnB1dCBlbGVtZW50IHRoZSB0eXBlYWhlYWQgZGlyZWN0aXZlIGlzIGFzc29jaWF0ZWQgd2l0aCBvbiBzZWxlY3Rpb24gKi9cclxuICAgIC8vIEBJbnB1dCgpIHByb3RlY3RlZCB0eXBlYWhlYWRGb2N1c09uU2VsZWN0OmJvb2xlYW47XHJcblxyXG4gIHB1YmxpYyBfY29udGFpbmVyOiBUeXBlYWhlYWRDb250YWluZXJDb21wb25lbnQ7XHJcbiAgcHVibGljIGlzVHlwZWFoZWFkT3B0aW9uc0xpc3RBY3RpdmUgPSBmYWxzZTtcclxuXHJcbiAgcHJvdGVjdGVkIGtleVVwRXZlbnRFbWl0dGVyOiBFdmVudEVtaXR0ZXI8YW55PiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcclxuICBwcm90ZWN0ZWQgX21hdGNoZXM6IFR5cGVhaGVhZE1hdGNoW107XHJcbiAgcHJvdGVjdGVkIHBsYWNlbWVudCA9ICdib3R0b20tbGVmdCc7XHJcbiAgLy8gcHJvdGVjdGVkIHBvcHVwOkNvbXBvbmVudFJlZjxUeXBlYWhlYWRDb250YWluZXJDb21wb25lbnQ+O1xyXG5cclxuICBwcm90ZWN0ZWQgbmdDb250cm9sOiBOZ0NvbnRyb2w7XHJcbiAgcHJvdGVjdGVkIHZpZXdDb250YWluZXJSZWY6IFZpZXdDb250YWluZXJSZWY7XHJcbiAgcHJvdGVjdGVkIGVsZW1lbnQ6IEVsZW1lbnRSZWY7XHJcbiAgcHJvdGVjdGVkIHJlbmRlcmVyOiBSZW5kZXJlcjI7XHJcblxyXG4gIHByaXZhdGUgX3R5cGVhaGVhZDogQ29tcG9uZW50TG9hZGVyPFR5cGVhaGVhZENvbnRhaW5lckNvbXBvbmVudD47XHJcblxyXG4gIEBIb3N0TGlzdGVuZXIoJ2tleXVwJywgWyckZXZlbnQnXSlcclxuICBwdWJsaWMgb25DaGFuZ2UoZTogYW55KTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5fY29udGFpbmVyKSB7XHJcbiAgICAgIC8vIGVzY1xyXG4gICAgICBpZiAoZS5rZXlDb2RlID09PSAyNykge1xyXG4gICAgICAgIHRoaXMuaGlkZSgpO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gdXBcclxuICAgICAgaWYgKGUua2V5Q29kZSA9PT0gMzgpIHtcclxuICAgICAgICB0aGlzLl9jb250YWluZXIucHJldkFjdGl2ZU1hdGNoKCk7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBkb3duXHJcbiAgICAgIGlmIChlLmtleUNvZGUgPT09IDQwKSB7XHJcbiAgICAgICAgdGhpcy5fY29udGFpbmVyLm5leHRBY3RpdmVNYXRjaCgpO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gZW50ZXJcclxuICAgICAgaWYgKGUua2V5Q29kZSA9PT0gMTMpIHtcclxuICAgICAgICB0aGlzLl9jb250YWluZXIuc2VsZWN0QWN0aXZlTWF0Y2goKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBGb3IgYDxpbnB1dD5gcywgdXNlIHRoZSBgdmFsdWVgIHByb3BlcnR5LiBGb3Igb3RoZXJzIHRoYXQgZG9uJ3QgaGF2ZSBhXHJcbiAgICAvLyBgdmFsdWVgIChzdWNoIGFzIGA8c3BhbiBjb250ZW50ZWRpdGFibGU9XCJ0cnVlXCI+YCwgdXNlIGBpbm5lclRleHRgLlxyXG4gICAgY29uc3QgdmFsdWUgPSBlLnRhcmdldC52YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgID8gZS50YXJnZXQudmFsdWVcclxuICAgICAgOiBlLnRhcmdldC5pbm5lclRleHQ7XHJcbiAgICBpZiAodmFsdWUudHJpbSgpLmxlbmd0aCA+PSB0aGlzLnR5cGVhaGVhZE1pbkxlbmd0aCkge1xyXG4gICAgICB0aGlzLnR5cGVhaGVhZExvYWRpbmcuZW1pdCh0cnVlKTtcclxuICAgICAgdGhpcy5rZXlVcEV2ZW50RW1pdHRlci5lbWl0KGUudGFyZ2V0LnZhbHVlKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMudHlwZWFoZWFkTG9hZGluZy5lbWl0KGZhbHNlKTtcclxuICAgICAgdGhpcy50eXBlYWhlYWROb1Jlc3VsdHMuZW1pdChmYWxzZSk7XHJcbiAgICAgIHRoaXMuaGlkZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgQEhvc3RMaXN0ZW5lcignZm9jdXMnKVxyXG4gIHB1YmxpYyBvbkZvY3VzKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMudHlwZWFoZWFkTWluTGVuZ3RoID09PSAwKSB7XHJcbiAgICAgIHRoaXMudHlwZWFoZWFkTG9hZGluZy5lbWl0KHRydWUpO1xyXG4gICAgICB0aGlzLmtleVVwRXZlbnRFbWl0dGVyLmVtaXQoJycpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgQEhvc3RMaXN0ZW5lcignYmx1cicpXHJcbiAgcHVibGljIG9uQmx1cigpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLl9jb250YWluZXIgJiYgIXRoaXMuX2NvbnRhaW5lci5pc0ZvY3VzZWQpIHtcclxuICAgICAgdGhpcy50eXBlYWhlYWRPbkJsdXIuZW1pdCh0aGlzLl9jb250YWluZXIuYWN0aXZlKTtcclxuICAgICAgdGhpcy5oaWRlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBASG9zdExpc3RlbmVyKCdrZXlkb3duJywgWyckZXZlbnQnXSlcclxuICBwdWJsaWMgb25LZXlkb3duKGU6IGFueSk6IHZvaWQge1xyXG4gICAgLy8gbm8gY29udGFpbmVyIC0gbm8gcHJvYmxlbXNcclxuICAgIGlmICghdGhpcy5fY29udGFpbmVyKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBpZiBpdGVtcyBpcyB2aXNpYmxlIC0gcHJldmVudCBmb3JtIHN1Ym1pdGlvblxyXG4gICAgaWYgKGUua2V5Q29kZSA9PT0gMTMpIHtcclxuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgY29uc3RydWN0b3IoY29udHJvbDogTmdDb250cm9sLCB2aWV3Q29udGFpbmVyUmVmOiBWaWV3Q29udGFpbmVyUmVmLCBlbGVtZW50OiBFbGVtZW50UmVmLCByZW5kZXJlcjogUmVuZGVyZXIyLCBjaXM6IENvbXBvbmVudExvYWRlckZhY3RvcnkpIHtcclxuICAgIHRoaXMuZWxlbWVudCA9IGVsZW1lbnQ7XHJcbiAgICB0aGlzLm5nQ29udHJvbCA9IGNvbnRyb2w7XHJcbiAgICB0aGlzLnZpZXdDb250YWluZXJSZWYgPSB2aWV3Q29udGFpbmVyUmVmO1xyXG4gICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyO1xyXG4gICAgdGhpcy5fdHlwZWFoZWFkID0gY2lzXHJcbiAgICAgIC5jcmVhdGVMb2FkZXI8VHlwZWFoZWFkQ29udGFpbmVyQ29tcG9uZW50PihlbGVtZW50LCB2aWV3Q29udGFpbmVyUmVmLCByZW5kZXJlcik7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgbmdPbkluaXQoKTogdm9pZCB7XHJcbiAgICB0aGlzLnR5cGVhaGVhZE9wdGlvbnNMaW1pdCA9IHRoaXMudHlwZWFoZWFkT3B0aW9uc0xpbWl0IHx8IDIwO1xyXG4gICAgdGhpcy50eXBlYWhlYWRNaW5MZW5ndGggPSB0aGlzLnR5cGVhaGVhZE1pbkxlbmd0aCA9PT0gdm9pZCAwXHJcbiAgICAgID8gMVxyXG4gICAgICA6IHRoaXMudHlwZWFoZWFkTWluTGVuZ3RoO1xyXG4gICAgdGhpcy50eXBlYWhlYWRXYWl0TXMgPSB0aGlzLnR5cGVhaGVhZFdhaXRNcyB8fCAwO1xyXG5cclxuICAgIC8vIGFzeW5jIHNob3VsZCBiZSBmYWxzZSBpbiBjYXNlIG9mIGFycmF5XHJcbiAgICBpZiAodGhpcy50eXBlYWhlYWRBc3luYyA9PT0gdW5kZWZpbmVkICYmICEodGhpcy50eXBlYWhlYWQgaW5zdGFuY2VvZiBPYnNlcnZhYmxlKSkge1xyXG4gICAgICB0aGlzLnR5cGVhaGVhZEFzeW5jID0gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMudHlwZWFoZWFkIGluc3RhbmNlb2YgT2JzZXJ2YWJsZSkge1xyXG4gICAgICB0aGlzLnR5cGVhaGVhZEFzeW5jID0gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy50eXBlYWhlYWRBc3luYykge1xyXG4gICAgICB0aGlzLmFzeW5jQWN0aW9ucygpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5zeW5jQWN0aW9ucygpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHVibGljIGNoYW5nZU1vZGVsKG1hdGNoOiBUeXBlYWhlYWRNYXRjaCk6IHZvaWQge1xyXG4gICAgY29uc3QgdmFsdWVTdHI6IHN0cmluZyA9IG1hdGNoLnZhbHVlO1xyXG4gICAgdGhpcy5uZ0NvbnRyb2wudmlld1RvTW9kZWxVcGRhdGUodmFsdWVTdHIpO1xyXG4gICAgKHRoaXMubmdDb250cm9sLmNvbnRyb2wgYXMgRm9ybUNvbnRyb2wpLnNldFZhbHVlKHZhbHVlU3RyKTtcclxuICAgIHRoaXMuaGlkZSgpO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIGdldCBtYXRjaGVzKCk6IGFueVtdIHtcclxuICAgIHJldHVybiB0aGlzLl9tYXRjaGVzO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIHNob3coKTogdm9pZCB7XHJcbiAgICB0aGlzLl90eXBlYWhlYWRcclxuICAgICAgLmF0dGFjaChUeXBlYWhlYWRDb250YWluZXJDb21wb25lbnQpXHJcbiAgICAgIC8vIHRvZG86IGFkZCBhcHBlbmQgdG8gYm9keSwgYWZ0ZXIgdXBkYXRpbmcgcG9zaXRpb25pbmcgc2VydmljZVxyXG4gICAgICAudG8odGhpcy5jb250YWluZXIpXHJcbiAgICAgIC5wb3NpdGlvbih7YXR0YWNobWVudDogJ2JvdHRvbSBsZWZ0J30pXHJcbiAgICAgIC5zaG93KHtcclxuICAgICAgICB0eXBlYWhlYWRSZWY6IHRoaXMsXHJcbiAgICAgICAgcGxhY2VtZW50OiB0aGlzLnBsYWNlbWVudCxcclxuICAgICAgICBhbmltYXRpb246IGZhbHNlXHJcbiAgICAgIH0pO1xyXG5cclxuICAgIHRoaXMuX2NvbnRhaW5lciA9IHRoaXMuX3R5cGVhaGVhZC5pbnN0YW5jZTtcclxuICAgIHRoaXMuX2NvbnRhaW5lci5wYXJlbnQgPSB0aGlzO1xyXG4gICAgLy8gVGhpcyBpbXByb3ZlcyB0aGUgc3BlZWQgYXMgaXQgd29uJ3QgaGF2ZSB0byBiZSBkb25lIGZvciBlYWNoIGxpc3QgaXRlbVxyXG4gICAgY29uc3Qgbm9ybWFsaXplZFF1ZXJ5ID0gKHRoaXMudHlwZWFoZWFkTGF0aW5pemVcclxuICAgICAgPyBsYXRpbml6ZSh0aGlzLm5nQ29udHJvbC5jb250cm9sLnZhbHVlKVxyXG4gICAgICA6IHRoaXMubmdDb250cm9sLmNvbnRyb2wudmFsdWUpLnRvU3RyaW5nKClcclxuICAgICAgLnRvTG93ZXJDYXNlKCk7XHJcbiAgICB0aGlzLl9jb250YWluZXIucXVlcnkgPSB0aGlzLnR5cGVhaGVhZFNpbmdsZVdvcmRzXHJcbiAgICAgID8gdG9rZW5pemUobm9ybWFsaXplZFF1ZXJ5LCB0aGlzLnR5cGVhaGVhZFdvcmREZWxpbWl0ZXJzLCB0aGlzLnR5cGVhaGVhZFBocmFzZURlbGltaXRlcnMpXHJcbiAgICAgIDogbm9ybWFsaXplZFF1ZXJ5O1xyXG4gICAgdGhpcy5fY29udGFpbmVyLm1hdGNoZXMgPSB0aGlzLl9tYXRjaGVzO1xyXG4gICAgdGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBoaWRlKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuX3R5cGVhaGVhZC5pc1Nob3duKSB7XHJcbiAgICAgIHRoaXMuX3R5cGVhaGVhZC5oaWRlKCk7XHJcbiAgICAgIHRoaXMuX2NvbnRhaW5lciA9IG51bGw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgbmdPbkRlc3Ryb3koKTogYW55IHtcclxuICAgIHRoaXMuX3R5cGVhaGVhZC5kaXNwb3NlKCk7XHJcbiAgfVxyXG5cclxuICBwcm90ZWN0ZWQgYXN5bmNBY3Rpb25zKCk6IHZvaWQge1xyXG4gICAgdGhpcy5rZXlVcEV2ZW50RW1pdHRlci5waXBlKFxyXG4gICAgICBkZWJvdW5jZVRpbWUodGhpcy50eXBlYWhlYWRXYWl0TXMpLFxyXG4gICAgICBtZXJnZU1hcCgoKSA9PiB0aGlzLnR5cGVhaGVhZClcclxuICAgICkuc3Vic2NyaWJlKFxyXG4gICAgICAgIChtYXRjaGVzOiBhbnlbXSkgPT4ge1xyXG4gICAgICAgICAgdGhpcy5maW5hbGl6ZUFzeW5jQ2FsbChtYXRjaGVzKTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIChlcnI6IGFueSkgPT4ge1xyXG4gICAgICAgICAgY29uc29sZS5lcnJvcihlcnIpO1xyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICB9XHJcblxyXG4gIHByb3RlY3RlZCBzeW5jQWN0aW9ucygpOiB2b2lkIHtcclxuICAgIHRoaXMua2V5VXBFdmVudEVtaXR0ZXIucGlwZShcclxuICAgICAgZGVib3VuY2VUaW1lKHRoaXMudHlwZWFoZWFkV2FpdE1zKSxcclxuICAgICAgbWVyZ2VNYXAoKHZhbHVlOiBzdHJpbmcpID0+IHtcclxuICAgICAgICBjb25zdCBub3JtYWxpemVkUXVlcnkgPSB0aGlzLm5vcm1hbGl6ZVF1ZXJ5KHZhbHVlKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIGZyb20odGhpcy50eXBlYWhlYWQpLnBpcGUoXHJcbiAgICAgICAgICBmaWx0ZXIoKG9wdGlvbjogYW55KSA9PiB7XHJcbiAgICAgICAgICAgIHJldHVybiBvcHRpb24gJiYgdGhpcy50ZXN0TWF0Y2godGhpcy5ub3JtYWxpemVPcHRpb24ob3B0aW9uKSwgbm9ybWFsaXplZFF1ZXJ5KTtcclxuICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgdG9BcnJheSgpXHJcbiAgICAgICAgKTtcclxuICAgICAgfSkpXHJcbiAgICAgIC5zdWJzY3JpYmUoXHJcbiAgICAgICAgKG1hdGNoZXM6IGFueVtdKSA9PiB7XHJcbiAgICAgICAgICB0aGlzLmZpbmFsaXplQXN5bmNDYWxsKG1hdGNoZXMpO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgKGVycjogYW55KSA9PiB7XHJcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGVycik7XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIG5vcm1hbGl6ZU9wdGlvbihvcHRpb246IGFueSk6IGFueSB7XHJcbiAgICBjb25zdCBvcHRpb25WYWx1ZTogc3RyaW5nID0gZ2V0VmFsdWVGcm9tT2JqZWN0KG9wdGlvbiwgdGhpcy50eXBlYWhlYWRPcHRpb25GaWVsZCk7XHJcbiAgICBjb25zdCBub3JtYWxpemVkT3B0aW9uID0gdGhpcy50eXBlYWhlYWRMYXRpbml6ZVxyXG4gICAgICA/IGxhdGluaXplKG9wdGlvblZhbHVlKVxyXG4gICAgICA6IG9wdGlvblZhbHVlO1xyXG5cclxuICAgIHJldHVybiBub3JtYWxpemVkT3B0aW9uLnRvTG93ZXJDYXNlKCk7XHJcbiAgfVxyXG5cclxuICBwcm90ZWN0ZWQgbm9ybWFsaXplUXVlcnkodmFsdWU6IHN0cmluZyk6IGFueSB7XHJcbiAgICAvLyBJZiBzaW5nbGVXb3JkcywgYnJlYWsgbW9kZWwgaGVyZSB0byBub3QgYmUgZG9pbmcgZXh0cmEgd29yayBvbiBlYWNoXHJcbiAgICAvLyBpdGVyYXRpb25cclxuICAgIGxldCBub3JtYWxpemVkUXVlcnk6IGFueSA9XHJcbiAgICAgICh0aGlzLnR5cGVhaGVhZExhdGluaXplID8gbGF0aW5pemUodmFsdWUpIDogdmFsdWUpXHJcbiAgICAgICAgLnRvU3RyaW5nKClcclxuICAgICAgICAudG9Mb3dlckNhc2UoKTtcclxuICAgIG5vcm1hbGl6ZWRRdWVyeSA9IHRoaXMudHlwZWFoZWFkU2luZ2xlV29yZHNcclxuICAgICAgPyB0b2tlbml6ZShub3JtYWxpemVkUXVlcnksIHRoaXMudHlwZWFoZWFkV29yZERlbGltaXRlcnMsIHRoaXMudHlwZWFoZWFkUGhyYXNlRGVsaW1pdGVycylcclxuICAgICAgOiBub3JtYWxpemVkUXVlcnk7XHJcblxyXG4gICAgcmV0dXJuIG5vcm1hbGl6ZWRRdWVyeTtcclxuICB9XHJcblxyXG4gIHByb3RlY3RlZCB0ZXN0TWF0Y2gobWF0Y2g6IHN0cmluZywgdGVzdDogYW55KTogYm9vbGVhbiB7XHJcbiAgICBsZXQgc3BhY2VMZW5ndGg6IG51bWJlcjtcclxuXHJcbiAgICBpZiAodHlwZW9mIHRlc3QgPT09ICdvYmplY3QnKSB7XHJcbiAgICAgIHNwYWNlTGVuZ3RoID0gdGVzdC5sZW5ndGg7XHJcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc3BhY2VMZW5ndGg7IGkgKz0gMSkge1xyXG4gICAgICAgIGlmICh0ZXN0W2ldLmxlbmd0aCA+IDAgJiYgbWF0Y2guaW5kZXhPZih0ZXN0W2ldKSA8IDApIHtcclxuICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gbWF0Y2guaW5kZXhPZih0ZXN0KSA+PSAwO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIGZpbmFsaXplQXN5bmNDYWxsKG1hdGNoZXM6IGFueVtdKTogdm9pZCB7XHJcbiAgICB0aGlzLnByZXBhcmVNYXRjaGVzKG1hdGNoZXMpO1xyXG5cclxuICAgIHRoaXMudHlwZWFoZWFkTG9hZGluZy5lbWl0KGZhbHNlKTtcclxuICAgIHRoaXMudHlwZWFoZWFkTm9SZXN1bHRzLmVtaXQoIXRoaXMuaGFzTWF0Y2hlcygpKTtcclxuXHJcbiAgICBpZiAoIXRoaXMuaGFzTWF0Y2hlcygpKSB7XHJcbiAgICAgIHRoaXMuaGlkZSgpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMuX2NvbnRhaW5lcikge1xyXG4gICAgICAvLyBUaGlzIGltcHJvdmVzIHRoZSBzcGVlZCBhcyBpdCB3b24ndCBoYXZlIHRvIGJlIGRvbmUgZm9yIGVhY2ggbGlzdCBpdGVtXHJcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWRRdWVyeSA9ICh0aGlzLnR5cGVhaGVhZExhdGluaXplXHJcbiAgICAgICAgPyBsYXRpbml6ZSh0aGlzLm5nQ29udHJvbC5jb250cm9sLnZhbHVlKVxyXG4gICAgICAgIDogdGhpcy5uZ0NvbnRyb2wuY29udHJvbC52YWx1ZSkudG9TdHJpbmcoKVxyXG4gICAgICAgIC50b0xvd2VyQ2FzZSgpO1xyXG4gICAgICB0aGlzLl9jb250YWluZXIucXVlcnkgPSB0aGlzLnR5cGVhaGVhZFNpbmdsZVdvcmRzXHJcbiAgICAgICAgPyB0b2tlbml6ZShub3JtYWxpemVkUXVlcnksIHRoaXMudHlwZWFoZWFkV29yZERlbGltaXRlcnMsIHRoaXMudHlwZWFoZWFkUGhyYXNlRGVsaW1pdGVycylcclxuICAgICAgICA6IG5vcm1hbGl6ZWRRdWVyeTtcclxuICAgICAgdGhpcy5fY29udGFpbmVyLm1hdGNoZXMgPSB0aGlzLl9tYXRjaGVzO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5zaG93KCk7XHJcbiAgICB