fundamental-ngx
Version:
SAP Fundamentals, implemented in Angular
567 lines • 45.9 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { Component, ContentChildren, EventEmitter, forwardRef, HostBinding, HostListener, Input, Output, QueryList, TemplateRef, ViewEncapsulation } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { OptionComponent } from './option/option.component';
import { defer, merge, Subject } from 'rxjs';
import { startWith, switchMap, takeUntil } from 'rxjs/operators';
/**
* Select component intended to mimic the behaviour of the native select element.
*/
export class SelectComponent {
constructor() {
/**
* @hidden
*/
this.fdDropdownClass = true;
/**
* Whether the select component is disabled.
*/
this.disabled = false;
/**
* Open state of the select.
*/
this.isOpen = false;
/**
* Popper.js options of the popover.
*/
this.popperOptions = {
placement: 'bottom-start',
modifiers: {
preventOverflow: {
enabled: true,
escapeWithReference: true,
boundariesElement: 'scrollParent'
}
}
};
/**
* Preset options for the popover body width.
* * `at-least` will apply a minimum width to the body equivalent to the width of the control.
* * `equal` will apply a width to the body equivalent to the width of the control.
* * Leave blank for no effect.
*/
this.fillControlMode = 'at-least';
/**
* Event emitted when the popover open state changes.
*/
this.isOpenChange = new EventEmitter();
/**
* Event emitted when the selected value of the select changes.
*/
this.valueChange = new EventEmitter();
/**
* Subject triggered when the component is destroyed.
*/
this.destroy$ = new Subject();
/**
* Observable triggered when an option has its selectedChange event fire.
*/
this.optionsStatusChanges = (/** @type {?} */ (defer((/**
* @return {?}
*/
() => {
/** @type {?} */
const options = this.options;
if (options) {
return options.changes.pipe(startWith(options), switchMap((/**
* @return {?}
*/
() => merge(...options.map((/**
* @param {?} option
* @return {?}
*/
option => option.selectedChange))))));
}
}))));
/**
* @hidden
*/
this.onChange = (/**
* @return {?}
*/
() => { });
/**
* @hidden
*/
this.onTouched = (/**
* @return {?}
*/
() => { });
}
/**
* @hidden
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
if (changes.value) {
setTimeout((/**
* @return {?}
*/
() => {
if (this.value) {
this.selectValue(this.value, false);
}
}));
}
}
/**
* @hidden
* @return {?}
*/
ngAfterContentInit() {
// If the observable state changes, reset the options and initialize selection.
this.options.changes.pipe(startWith(null), takeUntil(this.destroy$)).subscribe((/**
* @return {?}
*/
() => {
this.resetOptions();
this.initSelection();
}));
}
/**
* @hidden
* @return {?}
*/
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
/**
* Toggles the open state of the select.
* @return {?}
*/
toggle() {
if (this.isOpen && !this.disabled) {
this.close();
}
else {
this.open();
}
}
/**
* Opens the select popover body.
* @return {?}
*/
open() {
if (!this.isOpen && !this.disabled) {
this.isOpen = true;
this.isOpenChange.emit(this.isOpen);
}
}
/**
* Closes the select popover body.
* @return {?}
*/
close() {
if (this.isOpen && !this.disabled) {
this.isOpen = false;
this.isOpenChange.emit(this.isOpen);
}
}
/**
* @hidden
* @param {?} fn
* @return {?}
*/
registerOnChange(fn) {
this.onChange = fn;
}
/**
* @hidden
* @param {?} fn
* @return {?}
*/
registerOnTouched(fn) {
this.onTouched = fn;
}
/**
* @hidden
* @param {?} isDisabled
* @return {?}
*/
setDisabledState(isDisabled) {
this.disabled = isDisabled;
}
/**
* @hidden
* @param {?} value
* @return {?}
*/
writeValue(value) {
if (this.options) {
this.selectValue(value, false);
}
else {
// Defer the selection of the value to support forms
Promise.resolve().then((/**
* @return {?}
*/
() => {
if (this.options) {
this.selectValue(value, false);
}
}));
}
}
/**
* Returns the current trigger value if there is a selected option. Otherwise, returns the placeholder.
* @return {?}
*/
get triggerValue() {
return this.selected ? this.selected.viewValueText : this.placeholder;
}
/**
* @hidden
* @param {?} event
* @return {?}
*/
keydownHandler(event) {
switch (event.code) {
case ('ArrowUp'): {
event.preventDefault();
this.decrementFocused();
break;
}
case ('ArrowDown'): {
event.preventDefault();
this.incrementFocused();
break;
}
}
}
/**
* Selects an option by option component reference. Preferred method of selection.
* @private
* @param {?} option The option component to search for.
* @param {?=} fireEvents Whether to fire change events.
* @return {?}
*/
selectOption(option, fireEvents = true) {
if (!this.isOptionActive(option)) {
if (this.selected) {
this.selected.setSelected(false, false);
}
option.setSelected(true, false);
this.selected = option;
this.updateValue(fireEvents);
this.close();
return option;
}
return;
}
/**
* Selects an option by value. If two components have the same value, the first one found is selected.
* Recommend using selectOption generally.
* @private
* @param {?} value Value to search for.
* @param {?=} fireEvents Whether to fire change events.
* @return {?}
*/
selectValue(value, fireEvents = true) {
/** @type {?} */
const matchOption = this.options.find((/**
* @param {?} option
* @return {?}
*/
(option) => {
return option.value != null && option.value === value;
}));
// If not match is found, set everything to null
// This is mostly only for cases where a user removes an active option
if (!matchOption) {
this.unselectOptions();
return;
}
// If match is found, select the new value
if (matchOption && !this.isOptionActive(matchOption)) {
if (this.selected) {
this.selected.setSelected(false, false);
}
matchOption.setSelected(true, false);
this.selected = matchOption;
this.updateValue(fireEvents);
this.close();
}
return matchOption;
}
/**
* Updates the value parameter with optional events.
* @private
* @param {?=} fireEvents If true, function fires valueChange, onChange and onTouched events.
* @return {?}
*/
updateValue(fireEvents = true) {
this.value = this.selected.value;
if (fireEvents) {
this.valueChange.emit(this.value);
this.onChange(this.value);
this.onTouched();
}
}
/**
* Function used to reset the options state.
* @private
* @return {?}
*/
resetOptions() {
// Create observable that fires when the options change or the component is destroyed.
/** @type {?} */
const destroyCurrentObs = merge(this.options.changes, this.destroy$);
// Subscribe to observable defined in component properties which fires when an option is clicked.
// Destroy if the observable defined above triggers.
this.optionsStatusChanges.pipe(takeUntil(destroyCurrentObs)).subscribe((/**
* @param {?} instance
* @return {?}
*/
(instance) => {
this.selectOption(instance);
}));
}
/**
* Selection initialization when a change occurs in options.
* @private
* @return {?}
*/
initSelection() {
if (this.value) {
this.selected = undefined;
this.selectValue(this.value, false);
}
}
/**
* Function that tests whether the tested option is currently selected.
* @private
* @param {?} option Option to test against the selected option.
* @return {?}
*/
isOptionActive(option) {
return option && this.selected && option === this.selected;
}
/**
* Method that focuses the next option in the list, or the first one if the last one is currently focused.
* @private
* @return {?}
*/
incrementFocused() {
// Get active focused element
/** @type {?} */
const activeElement = document.activeElement;
// Get corresponding option element to the above
/** @type {?} */
const correspondingOption = this.options.find((/**
* @param {?} option
* @return {?}
*/
option => {
return option.getHtmlElement() === activeElement;
}));
if (correspondingOption) {
/** @type {?} */
const arrayOptions = this.options.toArray();
/** @type {?} */
const index = arrayOptions.indexOf(correspondingOption);
// If active option is the last option, focus the first one
// Otherwise, focus the next option.
if (index === this.options.length - 1) {
arrayOptions[0].focus();
}
else {
arrayOptions[index + 1].focus();
}
}
else if (this.options) {
this.options.first.focus();
}
}
/**
* Method that focuses the previous option in the list, or the last one if the last one is currently focused.
* @private
* @return {?}
*/
decrementFocused() {
// Get active focused element
/** @type {?} */
const activeElement = document.activeElement;
// Get corresponding option element to the above
/** @type {?} */
const correspondingOption = this.options.find((/**
* @param {?} option
* @return {?}
*/
option => {
return option.getHtmlElement() === activeElement;
}));
// If active option is the first option, focus the last one
// Otherwise, focus the previous option.
if (correspondingOption) {
/** @type {?} */
const arrayOptions = this.options.toArray();
/** @type {?} */
const index = arrayOptions.indexOf(correspondingOption);
if (index === 0) {
arrayOptions[this.options.length - 1].focus();
}
else {
arrayOptions[index - 1].focus();
}
}
else if (this.options) {
this.options.first.focus();
}
}
/**
* Method used to handle cases where a user removes the currently active option.
* The timeout is required because this can happen after the view has been checked.
* @private
* @return {?}
*/
unselectOptions() {
setTimeout((/**
* @return {?}
*/
() => {
if (this.selected) {
this.selected.setSelected(false, false);
}
this.selected = undefined;
this.value = undefined;
this.valueChange.emit(undefined);
this.onChange(undefined);
}));
}
}
SelectComponent.decorators = [
{ type: Component, args: [{
selector: 'fd-select',
template: "<fd-popover [(isOpen)]=\"isOpen\"\n (isOpenChange)=\"isOpenChange.emit($event)\"\n [options]=\"popperOptions\"\n [fillControlMode]=\"fillControlMode\"\n [appendTo]=\"appendTo\"\n class=\"fd-select-popover-custom\">\n <fd-popover-control>\n <ng-container *ngIf=\"triggerTemplate\">\n <ng-container *ngTemplateOutlet=\"triggerTemplate; context: {$implicit: this}\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"!triggerTemplate\">\n <button class=\"fd-dropdown__control fd-button fd-select-button-custom\"\n [attr.aria-expanded]=\"isOpen\"\n aria-haspopup=\"true\"\n [disabled]=\"disabled\">\n <span class=\"fd-select-text-custom\">{{triggerValue}}</span>\n </button>\n </ng-container>\n </fd-popover-control>\n <fd-popover-body>\n <ng-content></ng-content>\n </fd-popover-body>\n</fd-popover>\n",
encapsulation: ViewEncapsulation.None,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((/**
* @return {?}
*/
() => SelectComponent)),
multi: true
}
],
host: {
'[class.fd-select-custom]': 'true',
'role': 'listbox',
},
styles: [".fd-select-custom{display:inline-block;width:100%}.fd-select-custom .fd-select-popover-custom{display:block}.fd-select-custom .fd-select-popover-custom fd-popover-container{min-width:100%;overflow:auto}.fd-select-custom .fd-select-button-custom{display:flex;align-items:flex-end;justify-content:space-between}.fd-select-custom .fd-select-button-custom::after{flex-shrink:0;margin-top:0}.fd-select-custom .fd-select-text-custom{text-overflow:ellipsis;white-space:nowrap;overflow-x:hidden}"]
}] }
];
SelectComponent.propDecorators = {
fdDropdownClass: [{ type: HostBinding, args: ['class.fd-dropdown',] }],
options: [{ type: ContentChildren, args: [OptionComponent, { descendants: true },] }],
disabled: [{ type: Input }],
placeholder: [{ type: Input }],
isOpen: [{ type: Input }],
value: [{ type: Input }],
popperOptions: [{ type: Input }],
fillControlMode: [{ type: Input }],
triggerTemplate: [{ type: Input }],
appendTo: [{ type: Input }],
isOpenChange: [{ type: Output }],
valueChange: [{ type: Output }],
keydownHandler: [{ type: HostListener, args: ['keydown', ['$event'],] }]
};
if (false) {
/**
* @hidden
* @type {?}
*/
SelectComponent.prototype.fdDropdownClass;
/**
* @hidden
* @type {?}
*/
SelectComponent.prototype.options;
/**
* Whether the select component is disabled.
* @type {?}
*/
SelectComponent.prototype.disabled;
/**
* Placeholder for the select. Appears in the triggerbox if no option is selected.
* @type {?}
*/
SelectComponent.prototype.placeholder;
/**
* Open state of the select.
* @type {?}
*/
SelectComponent.prototype.isOpen;
/**
* Current value of the selected option.
* @type {?}
*/
SelectComponent.prototype.value;
/**
* Popper.js options of the popover.
* @type {?}
*/
SelectComponent.prototype.popperOptions;
/**
* Preset options for the popover body width.
* * `at-least` will apply a minimum width to the body equivalent to the width of the control.
* * `equal` will apply a width to the body equivalent to the width of the control.
* * Leave blank for no effect.
* @type {?}
*/
SelectComponent.prototype.fillControlMode;
/**
* Template with which to display the trigger box.
* @type {?}
*/
SelectComponent.prototype.triggerTemplate;
/**
* The element to which the popover should be appended.
* @type {?}
*/
SelectComponent.prototype.appendTo;
/**
* Event emitted when the popover open state changes.
* @type {?}
*/
SelectComponent.prototype.isOpenChange;
/**
* Event emitted when the selected value of the select changes.
* @type {?}
*/
SelectComponent.prototype.valueChange;
/**
* Current selected option component reference.
* @type {?}
* @private
*/
SelectComponent.prototype.selected;
/**
* Subject triggered when the component is destroyed.
* @type {?}
* @private
*/
SelectComponent.prototype.destroy$;
/**
* Observable triggered when an option has its selectedChange event fire.
* @type {?}
* @private
*/
SelectComponent.prototype.optionsStatusChanges;
/**
* @hidden
* @type {?}
*/
SelectComponent.prototype.onChange;
/**
* @hidden
* @type {?}
*/
SelectComponent.prototype.onTouched;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VsZWN0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL2Z1bmRhbWVudGFsLW5neC8iLCJzb3VyY2VzIjpbImxpYi9zZWxlY3Qvc2VsZWN0LmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsT0FBTyxFQUVILFNBQVMsRUFDVCxlQUFlLEVBQ2YsWUFBWSxFQUFFLFVBQVUsRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUNuRCxLQUFLLEVBQ0wsTUFBTSxFQUNOLFNBQVMsRUFBaUIsV0FBVyxFQUNyQyxpQkFBaUIsRUFDcEIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUF3QixpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBYyxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDekQsT0FBTyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7Ozs7QUF3QmpFLE1BQU0sT0FBTyxlQUFlO0lBakI1Qjs7OztRQXFCSSxvQkFBZSxHQUFZLElBQUksQ0FBQzs7OztRQVFoQyxhQUFRLEdBQVksS0FBSyxDQUFDOzs7O1FBUTFCLFdBQU0sR0FBWSxLQUFLLENBQUM7Ozs7UUFReEIsa0JBQWEsR0FBa0I7WUFDM0IsU0FBUyxFQUFFLGNBQWM7WUFDekIsU0FBUyxFQUFFO2dCQUNQLGVBQWUsRUFBRTtvQkFDYixPQUFPLEVBQUUsSUFBSTtvQkFDYixtQkFBbUIsRUFBRSxJQUFJO29CQUN6QixpQkFBaUIsRUFBRSxjQUFjO2lCQUNwQzthQUNKO1NBQ0osQ0FBQzs7Ozs7OztRQVNGLG9CQUFlLEdBQW9CLFVBQVUsQ0FBQzs7OztRQVlyQyxpQkFBWSxHQUNmLElBQUksWUFBWSxFQUFXLENBQUM7Ozs7UUFJekIsZ0JBQVcsR0FDZCxJQUFJLFlBQVksRUFB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V0FBVyxTQUFDLG1CQUFtQjtzQkFJL0IsZUFBZSxTQUFDLGVBQWUsRUFBRSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUU7dUJBSXRELEtBQUs7MEJBSUwsS0FBSztxQkFJTCxLQUFLO29CQUlMLEtBQUs7NEJBSUwsS0FBSzs4QkFrQkwsS0FBSzs4QkFJTCxLQUFLO3VCQUlMLEtBQUs7MkJBSUwsTUFBTTswQkFLTixNQUFNOzZCQWtITixZQUFZLFNBQUMsU0FBUyxFQUFFLENBQUMsUUFBUSxDQUFDOzs7Ozs7O0lBN0tuQywwQ0FDZ0M7Ozs7O0lBR2hDLGtDQUNvQzs7Ozs7SUFHcEMsbUNBQzBCOzs7OztJQUcxQixzQ0FDb0I7Ozs7O0lBR3BCLGlDQUN3Qjs7Ozs7SUFHeEIsZ0NBQ1c7Ozs7O0lBR1gsd0NBVUU7Ozs7Ozs7O0lBUUYsMENBQzhDOzs7OztJQUc5QywwQ0FDa0M7Ozs7O0lBR2xDLG1DQUMrQjs7Ozs7SUFHL0IsdUNBRWtDOzs7OztJQUdsQyxzQ0FFOEI7Ozs7OztJQUc5QixtQ0FBa0M7Ozs7OztJQUdsQyxtQ0FBK0Q7Ozs7OztJQUcvRCwrQ0FRa0M7Ozs7O0lBR2xDLG1DQUE4Qjs7Ozs7SUFHOUIsb0NBQStCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgICBBZnRlckNvbnRlbnRJbml0LFxuICAgIENvbXBvbmVudCxcbiAgICBDb250ZW50Q2hpbGRyZW4sXG4gICAgRXZlbnRFbWl0dGVyLCBmb3J3YXJkUmVmLCBIb3N0QmluZGluZywgSG9zdExpc3RlbmVyLFxuICAgIElucHV0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSxcbiAgICBPdXRwdXQsXG4gICAgUXVlcnlMaXN0LCBTaW1wbGVDaGFuZ2VzLCBUZW1wbGF0ZVJlZixcbiAgICBWaWV3RW5jYXBzdWxhdGlvblxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbnRyb2xWYWx1ZUFjY2Vzc29yLCBOR19WQUxVRV9BQ0NFU1NPUiB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IE9wdGlvbkNvbXBvbmVudCB9IGZyb20gJy4vb3B0aW9uL29wdGlvbi5jb21wb25lbnQnO1xuaW1wb3J0IHsgZGVmZXIsIG1lcmdlLCBPYnNlcnZhYmxlLCBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBzdGFydFdpdGgsIHN3aXRjaE1hcCwgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgUG9wcGVyT3B0aW9ucyB9IGZyb20gJ3BvcHBlci5qcyc7XG5pbXBvcnQgeyBQb3BvdmVyRmlsbE1vZGUgfSBmcm9tICcuLi9wb3BvdmVyL3BvcG92ZXItZGlyZWN0aXZlL3BvcG92ZXIuZGlyZWN0aXZlJztcblxuLyoqXG4gKiBTZWxlY3QgY29tcG9uZW50IGludGVuZGVkIHRvIG1pbWljIHRoZSBiZWhhdmlvdXIgb2YgdGhlIG5hdGl2ZSBzZWxlY3QgZWxlbWVudC5cbiAqL1xuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICdmZC1zZWxlY3QnLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9zZWxlY3QuY29tcG9uZW50Lmh0bWwnLFxuICAgIHN0eWxlVXJsczogWycuL3NlbGVjdC5jb21wb25lbnQuc2NzcyddLFxuICAgIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gICAgcHJvdmlkZXJzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICAgIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuICAgICAgICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gU2VsZWN0Q29tcG9uZW50KSxcbiAgICAgICAgICAgIG11bHRpOiB0cnVlXG4gICAgICAgIH1cbiAgICBdLFxuICAgIGhvc3Q6IHtcbiAgICAgICAgJ1tjbGFzcy5mZC1zZWxlY3QtY3VzdG9tXSc6ICd0cnVlJyxcbiAgICAgICAgJ3JvbGUnOiAnbGlzdGJveCcsXG4gICAgfVxufSlcbmV4cG9ydCBjbGFzcyBTZWxlY3RDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMsIEFmdGVyQ29udGVudEluaXQsIE9uRGVzdHJveSwgQ29udHJvbFZhbHVlQWNjZXNzb3Ige1xuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBASG9zdEJpbmRpbmcoJ2NsYXNzLmZkLWRyb3Bkb3duJylcbiAgICBmZERyb3Bkb3duQ2xhc3M6IGJvb2xlYW4gPSB0cnVlO1xuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBAQ29udGVudENoaWxkcmVuKE9wdGlvbkNvbXBvbmVudCwgeyBkZXNjZW5kYW50czogdHJ1ZSB9KVxuICAgIG9wdGlvbnM6IFF1ZXJ5TGlzdDxPcHRpb25Db21wb25lbnQ+O1xuXG4gICAgLyoqIFdoZXRoZXIgdGhlIHNlbGVjdCBjb21wb25lbnQgaXMgZGlzYWJsZWQuICovXG4gICAgQElucHV0KClcbiAgICBkaXNhYmxlZDogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgLyoqIFBsYWNlaG9sZGVyIGZvciB0aGUgc2VsZWN0LiBBcHBlYXJzIGluIHRoZSB0cmlnZ2VyYm94IGlmIG5vIG9wdGlvbiBpcyBzZWxlY3RlZC4gKi9cbiAgICBASW5wdXQoKVxuICAgIHBsYWNlaG9sZGVyOiBzdHJpbmc7XG5cbiAgICAvKiogT3BlbiBzdGF0ZSBvZiB0aGUgc2VsZWN0LiAqL1xuICAgIEBJbnB1dCgpXG4gICAgaXNPcGVuOiBib29sZWFuID0gZmFsc2U7XG5cbiAgICAvKiogQ3VycmVudCB2YWx1ZSBvZiB0aGUgc2VsZWN0ZWQgb3B0aW9uLiAqL1xuICAgIEBJbnB1dCgpXG4gICAgdmFsdWU6IGFueTtcblxuICAgIC8qKiBQb3BwZXIuanMgb3B0aW9ucyBvZiB0aGUgcG9wb3Zlci4gKi9cbiAgICBASW5wdXQoKVxuICAgIHBvcHBlck9wdGlvbnM6IFBvcHBlck9wdGlvbnMgPSB7XG4gICAgICAgIHBsYWNlbWVudDogJ2JvdHRvbS1zdGFydCcsXG4gICAgICAgIG1vZGlmaWVyczoge1xuICAgICAgICAgICAgcHJldmVudE92ZXJmbG93OiB7XG4gICAgICAgICAgICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBlc2NhcGVXaXRoUmVmZXJlbmNlOiB0cnVlLFxuICAgICAgICAgICAgICAgIGJvdW5kYXJpZXNFbGVtZW50OiAnc2Nyb2xsUGFyZW50J1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFByZXNldCBvcHRpb25zIGZvciB0aGUgcG9wb3ZlciBib2R5IHdpZHRoLlxuICAgICAqICogYGF0LWxlYXN0YCB3aWxsIGFwcGx5IGEgbWluaW11bSB3aWR0aCB0byB0aGUgYm9keSBlcXVpdmFsZW50IHRvIHRoZSB3aWR0aCBvZiB0aGUgY29udHJvbC5cbiAgICAgKiAqIGBlcXVhbGAgd2lsbCBhcHBseSBhIHdpZHRoIHRvIHRoZSBib2R5IGVxdWl2YWxlbnQgdG8gdGhlIHdpZHRoIG9mIHRoZSBjb250cm9sLlxuICAgICAqICogTGVhdmUgYmxhbmsgZm9yIG5vIGVmZmVjdC5cbiAgICAgKi9cbiAgICBASW5wdXQoKVxuICAgIGZpbGxDb250cm9sTW9kZTogUG9wb3ZlckZpbGxNb2RlID0gJ2F0LWxlYXN0JztcblxuICAgIC8qKiBUZW1wbGF0ZSB3aXRoIHdoaWNoIHRvIGRpc3BsYXkgdGhlIHRyaWdnZXIgYm94LiAqL1xuICAgIEBJbnB1dCgpXG4gICAgdHJpZ2dlclRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxhbnk+O1xuXG4gICAgLyoqIFRoZSBlbGVtZW50IHRvIHdoaWNoIHRoZSBwb3BvdmVyIHNob3VsZCBiZSBhcHBlbmRlZC4gKi9cbiAgICBASW5wdXQoKVxuICAgIGFwcGVuZFRvOiBIVE1MRWxlbWVudCB8ICdib2R5JztcblxuICAgIC8qKiBFdmVudCBlbWl0dGVkIHdoZW4gdGhlIHBvcG92ZXIgb3BlbiBzdGF0ZSBjaGFuZ2VzLiAqL1xuICAgIEBPdXRwdXQoKVxuICAgIHJlYWRvbmx5IGlzT3BlbkNoYW5nZTogRXZlbnRFbWl0dGVyPGJvb2xlYW4+XG4gICAgICAgID0gbmV3IEV2ZW50RW1pdHRlcjxib29sZWFuPigpO1xuXG4gICAgLyoqIEV2ZW50IGVtaXR0ZWQgd2hlbiB0aGUgc2VsZWN0ZWQgdmFsdWUgb2YgdGhlIHNlbGVjdCBjaGFuZ2VzLiAqL1xuICAgIEBPdXRwdXQoKVxuICAgIHJlYWRvbmx5IHZhbHVlQ2hhbmdlOiBFdmVudEVtaXR0ZXI8YW55PlxuICAgICAgICA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuXG4gICAgLyoqIEN1cnJlbnQgc2VsZWN0ZWQgb3B0aW9uIGNvbXBvbmVudCByZWZlcmVuY2UuICovXG4gICAgcHJpdmF0ZSBzZWxlY3RlZDogT3B0aW9uQ29tcG9uZW50O1xuXG4gICAgLyoqIFN1YmplY3QgdHJpZ2dlcmVkIHdoZW4gdGhlIGNvbXBvbmVudCBpcyBkZXN0cm95ZWQuICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBkZXN0cm95JDogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgICAvKiogT2JzZXJ2YWJsZSB0cmlnZ2VyZWQgd2hlbiBhbiBvcHRpb24gaGFzIGl0cyBzZWxlY3RlZENoYW5nZSBldmVudCBmaXJlLiAqL1xuICAgIHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uc1N0YXR1c0NoYW5nZXM6IE9ic2VydmFibGU8T3B0aW9uQ29tcG9uZW50PiA9IGRlZmVyKCgpID0+IHtcbiAgICAgICAgY29uc3Qgb3B0aW9ucyA9IHRoaXMub3B0aW9ucztcbiAgICAgICAgaWYgKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb25zLmNoYW5nZXMucGlwZShcbiAgICAgICAgICAgICAgICBzdGFydFdpdGgob3B0aW9ucyksXG4gICAgICAgICAgICAgICAgc3dpdGNoTWFwKCgpID0+IG1lcmdlKC4uLm9wdGlvbnMubWFwKG9wdGlvbiA9PiBvcHRpb24uc2VsZWN0ZWRDaGFuZ2UpKSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9KSBhcyBPYnNlcnZhYmxlPE9wdGlvbkNvbXBvbmVudD47XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIG9uQ2hhbmdlOiBGdW5jdGlvbiA9ICgpID0+IHt9O1xuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBvblRvdWNoZWQ6IEZ1bmN0aW9uID0gKCkgPT4ge307XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICAgICAgaWYgKGNoYW5nZXMudmFsdWUpIHtcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLnZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2VsZWN0VmFsdWUodGhpcy52YWx1ZSwgZmFsc2UpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBuZ0FmdGVyQ29udGVudEluaXQoKTogdm9pZCB7XG5cbiAgICAgICAgLy8gSWYgdGhlIG9ic2VydmFibGUgc3RhdGUgY2hhbmdlcywgcmVzZXQgdGhlIG9wdGlvbnMgYW5kIGluaXRpYWxpemUgc2VsZWN0aW9uLlxuICAgICAgICB0aGlzLm9wdGlvbnMuY2hhbmdlcy5waXBlKHN0YXJ0V2l0aChudWxsKSwgdGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKS5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5yZXNldE9wdGlvbnMoKTtcbiAgICAgICAgICAgIHRoaXMuaW5pdFNlbGVjdGlvbigpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICB0aGlzLmRlc3Ryb3kkLm5leHQoKTtcbiAgICAgICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xuICAgIH1cblxuICAgIC8qKiBUb2dnbGVzIHRoZSBvcGVuIHN0YXRlIG9mIHRoZSBzZWxlY3QuICovXG4gICAgdG9nZ2xlKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5pc09wZW4gJiYgIXRoaXMuZGlzYWJsZWQpIHtcbiAgICAgICAgICAgIHRoaXMuY2xvc2UoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMub3BlbigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIE9wZW5zIHRoZSBzZWxlY3QgcG9wb3ZlciBib2R5LiAqL1xuICAgIG9wZW4oKTogdm9pZCB7XG4gICAgICAgIGlmICghdGhpcy5pc09wZW4gJiYgIXRoaXMuZGlzYWJsZWQpIHtcbiAgICAgICAgICAgIHRoaXMuaXNPcGVuID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMuaXNPcGVuQ2hhbmdlLmVtaXQodGhpcy5pc09wZW4pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIENsb3NlcyB0aGUgc2VsZWN0IHBvcG92ZXIgYm9keS4gKi9cbiAgICBjbG9zZSgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuaXNPcGVuICYmICF0aGlzLmRpc2FibGVkKSB7XG4gICAgICAgICAgICB0aGlzLmlzT3BlbiA9IGZhbHNlO1xuICAgICAgICAgICAgdGhpcy5pc09wZW5DaGFuZ2UuZW1pdCh0aGlzLmlzT3Blbik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIHJlZ2lzdGVyT25DaGFuZ2UoZm46IGFueSk6IHZvaWQge1xuICAgICAgICB0aGlzLm9uQ2hhbmdlID0gZm47XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICByZWdpc3Rlck9uVG91Y2hlZChmbjogYW55KTogdm9pZCB7XG4gICAgICAgIHRoaXMub25Ub3VjaGVkID0gZm47XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBzZXREaXNhYmxlZFN0YXRlKGlzRGlzYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICAgICAgdGhpcy5kaXNhYmxlZCA9IGlzRGlzYWJsZWQ7XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICB3cml0ZVZhbHVlKHZhbHVlOiBhbnkpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucykge1xuICAgICAgICAgICAgdGhpcy5zZWxlY3RWYWx1ZSh2YWx1ZSwgZmFsc2UpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gRGVmZXIgdGhlIHNlbGVjdGlvbiBvZiB0aGUgdmFsdWUgdG8gc3VwcG9ydCBmb3Jtc1xuICAgICAgICAgICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMub3B0aW9ucykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnNlbGVjdFZhbHVlKHZhbHVlLCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogUmV0dXJucyB0aGUgY3VycmVudCB0cmlnZ2VyIHZhbHVlIGlmIHRoZXJlIGlzIGEgc2VsZWN0ZWQgb3B0aW9uLiBPdGhlcndpc2UsIHJldHVybnMgdGhlIHBsYWNlaG9sZGVyLiAqL1xuICAgIGdldCB0cmlnZ2VyVmFsdWUoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2VsZWN0ZWQgPyB0aGlzLnNlbGVjdGVkLnZpZXdWYWx1ZVRleHQgOiB0aGlzLnBsYWNlaG9sZGVyO1xuICAgIH1cblxuICAgIC8qKiBAaGlkZGVuICovXG4gICAgQEhvc3RMaXN0ZW5lcigna2V5ZG93bicsIFsnJGV2ZW50J10pXG4gICAga2V5ZG93bkhhbmRsZXIoZXZlbnQ6IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcbiAgICAgICAgc3dpdGNoIChldmVudC5jb2RlKSB7XG4gICAgICAgICAgICBjYXNlICgnQXJyb3dVcCcpOiB7XG4gICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICB0aGlzLmRlY3JlbWVudEZvY3VzZWQoKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgKCdBcnJvd0Rvd24nKToge1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgdGhpcy5pbmNyZW1lbnRGb2N1c2VkKCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZWxlY3RzIGFuIG9wdGlvbiBieSBvcHRpb24gY29tcG9uZW50IHJlZmVyZW5jZS4gUHJlZmVycmVkIG1ldGhvZCBvZiBzZWxlY3Rpb24uXG4gICAgICogQHBhcmFtIG9wdGlvbiBUaGUgb3B0aW9uIGNvbXBvbmVudCB0byBzZWFyY2ggZm9yLlxuICAgICAqIEBwYXJhbSBmaXJlRXZlbnRzIFdoZXRoZXIgdG8gZmlyZSBjaGFuZ2UgZXZlbnRzLlxuICAgICAqL1xuICAgIHByaXZhdGUgc2VsZWN0T3B0aW9uKG9wdGlvbjogT3B0aW9uQ29tcG9uZW50LCBmaXJlRXZlbnRzOiBib29sZWFuID0gdHJ1ZSk6IE9wdGlvbkNvbXBvbmVudCB8IHVuZGVmaW5lZCB7XG4gICAgICAgIGlmICghdGhpcy5pc09wdGlvbkFjdGl2ZShvcHRpb24pKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5zZWxlY3RlZCkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWQuc2V0U2VsZWN0ZWQoZmFsc2UsIGZhbHNlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIG9wdGlvbi5zZXRTZWxlY3RlZCh0cnVlLCBmYWxzZSk7XG4gICAgICAgICAgICB0aGlzLnNlbGVjdGVkID0gb3B0aW9uO1xuICAgICAgICAgICAgdGhpcy51cGRhdGVWYWx1ZShmaXJlRXZlbnRzKTtcbiAgICAgICAgICAgIHRoaXMuY2xvc2UoKTtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb247XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlbGVjdHMgYW4gb3B0aW9uIGJ5IHZhbHVlLiBJZiB0d28gY29tcG9uZW50cyBoYXZlIHRoZSBzYW1lIHZhbHVlLCB0aGUgZmlyc3Qgb25lIGZvdW5kIGlzIHNlbGVjdGVkLlxuICAgICAqIFJlY29tbWVuZCB1c2luZyBzZWxlY3RPcHRpb24gZ2VuZXJhbGx5LlxuICAgICAqIEBwYXJhbSB2YWx1ZSBWYWx1ZSB0byBzZWFyY2ggZm9yLlxuICAgICAqIEBwYXJhbSBmaXJlRXZlbnRzIFdoZXRoZXIgdG8gZmlyZSBjaGFuZ2UgZXZlbnRzLlxuICAgICAqL1xuICAgIHByaXZhdGUgc2VsZWN0VmFsdWUodmFsdWU6IGFueSwgZmlyZUV2ZW50czogYm9vbGVhbiA9IHRydWUpOiBPcHRpb25Db21wb25lbnQgfCB1bmRlZmluZWQge1xuICAgICAgICBjb25zdCBtYXRjaE9wdGlvbiA9IHRoaXMub3B0aW9ucy5maW5kKChvcHRpb246IE9wdGlvbkNvbXBvbmVudCkgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbi52YWx1ZSAhPSBudWxsICYmIG9wdGlvbi52YWx1ZSA9PT0gdmFsdWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIElmIG5vdCBtYXRjaCBpcyBmb3VuZCwgc2V0IGV2ZXJ5dGhpbmcgdG8gbnVsbFxuICAgICAgICAvLyBUaGlzIGlzIG1vc3RseSBvbmx5IGZvciBjYXNlcyB3aGVyZSBhIHVzZXIgcmVtb3ZlcyBhbiBhY3RpdmUgb3B0aW9uXG4gICAgICAgIGlmICghbWF0Y2hPcHRpb24pIHtcbiAgICAgICAgICAgIHRoaXMudW5zZWxlY3RPcHRpb25zKCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBJZiBtYXRjaCBpcyBmb3VuZCwgc2VsZWN0IHRoZSBuZXcgdmFsdWVcbiAgICAgICAgaWYgKG1hdGNoT3B0aW9uICYmICF0aGlzLmlzT3B0aW9uQWN0aXZlKG1hdGNoT3B0aW9uKSkge1xuICAgICAgICAgICAgaWYgKHRoaXMuc2VsZWN0ZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNlbGVjdGVkLnNldFNlbGVjdGVkKGZhbHNlLCBmYWxzZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBtYXRjaE9wdGlvbi5zZXRTZWxlY3RlZCh0cnVlLCBmYWxzZSk7XG4gICAgICAgICAgICB0aGlzLnNlbGVjdGVkID0gbWF0Y2hPcHRpb247XG5cbiAgICAgICAgICAgIHRoaXMudXBkYXRlVmFsdWUoZmlyZUV2ZW50cyk7XG4gICAgICAgICAgICB0aGlzLmNsb3NlKCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbWF0Y2hPcHRpb247XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgdmFsdWUgcGFyYW1ldGVyIHdpdGggb3B0aW9uYWwgZXZlbnRzLlxuICAgICAqIEBwYXJhbSBmaXJlRXZlbnRzIElmIHRydWUsIGZ1bmN0aW9uIGZpcmVzIHZhbHVlQ2hhbmdlLCBvbkNoYW5nZSBhbmQgb25Ub3VjaGVkIGV2ZW50cy5cbiAgICAgKi9cbiAgICBwcml2YXRlIHVwZGF0ZVZhbHVlKGZpcmVFdmVudHM6IGJvb2xlYW4gPSB0cnVlKTogdm9pZCB7XG4gICAgICAgIHRoaXMudmFsdWUgPSB0aGlzLnNlbGVjdGVkLnZhbHVlO1xuICAgICAgICBpZiAoZmlyZUV2ZW50cykge1xuICAgICAgICAgICAgdGhpcy52YWx1ZUNoYW5nZS5lbWl0KHRoaXMudmFsdWUpO1xuICAgICAgICAgICAgdGhpcy5vbkNoYW5nZSh0aGlzLnZhbHVlKTtcbiAgICAgICAgICAgIHRoaXMub25Ub3VjaGVkKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBGdW5jdGlvbiB1c2VkIHRvIHJlc2V0IHRoZSBvcHRpb25zIHN0YXRlLlxuICAgICAqL1xuICAgIHByaXZhdGUgcmVzZXRPcHRpb25zKCk6IHZvaWQge1xuICAgICAgICAvLyBDcmVhdGUgb2JzZXJ2YWJsZSB0aGF0IGZpcmVzIHdoZW4gdGhlIG9wdGlvbnMgY2hhbmdlIG9yIHRoZSBjb21wb25lbnQgaXMgZGVzdHJveWVkLlxuICAgICAgICBjb25zdCBkZXN0cm95Q3VycmVudE9icyA9IG1lcmdlKHRoaXMub3B0aW9ucy5jaGFuZ2VzLCB0aGlzLmRlc3Ryb3kkKTtcblxuICAgICAgICAvLyBTdWJzY3JpYmUgdG8gb2JzZXJ2YWJsZSBkZWZpbmVkIGluIGNvbXBvbmVudCBwcm9wZXJ0aWVzIHdoaWNoIGZpcmVzIHdoZW4gYW4gb3B0aW9uIGlzIGNsaWNrZWQuXG4gICAgICAgIC8vIERlc3Ryb3kgaWYgdGhlIG9ic2VydmFibGUgZGVmaW5lZCBhYm92ZSB0cmlnZ2Vycy5cbiAgICAgICAgdGhpcy5vcHRpb25zU3RhdHVzQ2hhbmdlcy5waXBlKHRha2VVbnRpbChkZXN0cm95Q3VycmVudE9icykpLnN1YnNjcmliZSgoaW5zdGFuY2U6IE9wdGlvbkNvbXBvbmVudCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5zZWxlY3RPcHRpb24oaW5zdGFuY2UpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKiogU2VsZWN0aW9uIGluaXRpYWxpemF0aW9uIHdoZW4gYSBjaGFuZ2Ugb2NjdXJzIGluIG9wdGlvbnMuICovXG4gICAgcHJpdmF0ZSBpbml0U2VsZWN0aW9uKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy52YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy5zZWxlY3RlZCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0VmFsdWUodGhpcy52YWx1ZSwgZmFsc2UpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRnVuY3Rpb24gdGhhdCB0ZXN0cyB3aGV0aGVyIHRoZSB0ZXN0ZWQgb3B0aW9uIGlzIGN1cnJlbnRseSBzZWxlY3RlZC5cbiAgICAgKiBAcGFyYW0gb3B0aW9uIE9wdGlvbiB0byB0ZXN0IGFnYWluc3QgdGhlIHNlbGVjdGVkIG9wdGlvbi5cbiAgICAgKi9cbiAgICBwcml2YXRlIGlzT3B0aW9uQWN0aXZlKG9wdGlvbjogT3B0aW9uQ29tcG9uZW50KTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBvcHRpb24gJiYgdGhpcy5zZWxlY3RlZCAmJiBvcHRpb24gPT09IHRoaXMuc2VsZWN0ZWQ7XG4gICAgfVxuXG4gICAgLyoqIE1ldGhvZCB0aGF0IGZvY3VzZXMgdGhlIG5leHQgb3B0aW9uIGluIHRoZSBsaXN0LCBvciB0aGUgZmlyc3Qgb25lIGlmIHRoZSBsYXN0IG9uZSBpcyBjdXJyZW50bHkgZm9jdXNlZC4gKi9cbiAgICBwcml2YXRlIGluY3JlbWVudEZvY3VzZWQoKTogdm9pZCB7XG5cbiAgICAgICAgLy8gR2V0IGFjdGl2ZSBmb2N1c2VkIGVsZW1lbnRcbiAgICAgICAgY29uc3QgYWN0aXZlRWxlbWVudCA9IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQ7XG5cbiAgICAgICAgLy8gR2V0IGNvcnJlc3BvbmRpbmcgb3B0aW9uIGVsZW1lbnQgdG8gdGhlIGFib3ZlXG4gICAgICAgIGNvbnN0IGNvcnJlc3BvbmRpbmdPcHRpb24gPSB0aGlzLm9wdGlvbnMuZmluZChvcHRpb24gPT4ge1xuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbi5nZXRIdG1sRWxlbWVudCgpID09PSBhY3RpdmVFbGVtZW50O1xuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoY29ycmVzcG9uZGluZ09wdGlvbikge1xuICAgICAgICAgICAgY29uc3QgYXJyYXlPcHRpb25zID0gdGhpcy5vcHRpb25zLnRvQXJyYXkoKTtcbiAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gYXJyYXlPcHRpb25zLmluZGV4T2YoY29ycmVzcG9uZGluZ09wdGlvbik7XG5cbiAgICAgICAgICAgIC8vIElmIGFjdGl2ZSBvcHRpb24gaXMgdGhlIGxhc3Qgb3B0aW9uLCBmb2N1cyB0aGUgZmlyc3Qgb25lXG4gICAgICAgICAgICAvLyBPdGhlcndpc2UsIGZvY3VzIHRoZSBuZXh0IG9wdGlvbi5cbiAgICAgICAgICAgIGlmIChpbmRleCA9PT0gdGhpcy5vcHRpb25zLmxlbmd0aCAtIDEpIHtcbiAgICAgICAgICAgICAgICBhcnJheU9wdGlvbnNbMF0uZm9jdXMoKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYXJyYXlPcHRpb25zW2luZGV4ICsgMV0uZm9jdXMoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLm9wdGlvbnMpIHtcbiAgICAgICAgICAgIHRoaXMub3B0aW9ucy5maXJzdC5mb2N1cygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIE1ldGhvZCB0aGF0IGZvY3VzZXMgdGhlIHByZXZpb3VzIG9wdGlvbiBpbiB0aGUgbGlzdCwgb3IgdGhlIGxhc3Qgb25lIGlmIHRoZSBsYXN0IG9uZSBpcyBjdXJyZW50bHkgZm9jdXNlZC4gKi9cbiAgICBwcml2YXRlIGRlY3JlbWVudEZvY3VzZWQoKTogdm9pZCB7XG5cbiAgICAgICAgLy8gR2V0IGFjdGl2ZSBmb2N1c2VkIGVsZW1lbnRcbiAgICAgICAgY29uc3QgYWN0aXZlRWxlbWVudCA9IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQ7XG5cbiAgICAgICAgLy8gR2V0IGNvcnJlc3BvbmRpbmcgb3B0aW9uIGVsZW1lbnQgdG8gdGhlIGFib3ZlXG4gICAgICAgIGNvbnN0IGNvcnJlc3BvbmRpbmdPcHRpb24gPSB0aGlzLm9wdGlvbnMuZmluZChvcHRpb24gPT4ge1xuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbi5nZXRIdG1sRWxlbWVudCgpID09PSBhY3RpdmVFbGVtZW50O1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBJZiBhY3RpdmUgb3B0aW9uIGlzIHRoZSBmaXJzdCBvcHRpb24sIGZvY3VzIHRoZSBsYXN0IG9uZVxuICAgICAgICAvLyBPdGhlcndpc2UsIGZvY3VzIHRoZSBwcmV2aW91cyBvcHRpb24uXG4gICAgICAgIGlmIChjb3JyZXNwb25kaW5nT3B0aW9uKSB7XG4gICAgICAgICAgICBjb25zdCBhcnJheU9wdGlvbnMgPSB0aGlzLm9wdGlvbnMudG9BcnJheSgpO1xuICAgICAgICAgICAgY29uc3QgaW5kZXggPSBhcnJheU9wdGlvbnMuaW5kZXhPZihjb3JyZXNwb25kaW5nT3B0aW9uKTtcblxuICAgICAgICAgICAgaWYgKGluZGV4ID09PSAwKSB7XG4gICAgICAgICAgICAgICAgYXJyYXlPcHRpb25zW3RoaXMub3B0aW9ucy5sZW5ndGggLSAxXS5mb2N1cygpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBhcnJheU9wdGlvbnNbaW5kZXggLSAxXS5mb2N1cygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHRoaXMub3B0aW9ucykge1xuICAgICAgICAgICAgdGhpcy5vcHRpb25zLmZpcnN0LmZvY3VzKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNZXRob2QgdXNlZCB0byBoYW5kbGUgY2FzZXMgd2hlcmUgYSB1c2VyIHJlbW92ZXMgdGhlIGN1cnJlbnRseSBhY3RpdmUgb3B0aW9uLlxuICAgICAqIFRoZSB0aW1lb3V0IGlzIHJlcXVpcmVkIGJlY2F1c2UgdGhpcyBjYW4gaGFwcGVuIGFmdGVyIHRoZSB2aWV3IGhhcyBiZWVuIGNoZWNrZWQuXG4gICAgICovXG4gICAgcHJpdmF0ZSB1bnNlbGVjdE9wdGlvbnMoKTogdm9pZCB7XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMuc2VsZWN0ZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNlbGVjdGVkLnNldFNlbGVjdGVkKGZhbHNlLCBmYWxzZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnNlbGVjdGVkID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgdGhpcy52YWx1ZSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHRoaXMudmFsdWVDaGFuZ2UuZW1pdCh1bmRlZmluZWQpO1xuICAgICAgICAgICAgdGhpcy5vbkNoYW5nZSh1bmRlZmluZWQpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbn1cbiJdfQ==