@webdev-tools/ng-nested-reactive-forms
Version:
Implement Nested FormControl for Angular Reactive Forms.
448 lines (433 loc) • 64.2 kB
JavaScript
import { EventEmitter, Injectable, Directive, HostListener, Input, Optional, Output, Renderer2, TemplateRef, ViewContainerRef, NgModule } from '@angular/core';
import { FormGroup, FormsModule, ReactiveFormsModule, Validators, FormArray, FormControl } from '@angular/forms';
import { ReplaySubject } from 'rxjs/internal/ReplaySubject';
import { takeWhile } from 'rxjs/operators';
import { CommonModule } from '@angular/common';
class NrfFormContext {
constructor(nrfForm) {
this.nrfForm = nrfForm;
this.$implicit = nrfForm;
this.formGroup = nrfForm.formGroup;
}
}
class NrfSubmitData {
constructor(nrfForm, $event) {
this.nrfForm = nrfForm;
this.event = $event;
this.formData = nrfForm.formData;
this.entity = nrfForm.nrfEntity;
this.formGroup = nrfForm.formGroup;
}
}
function cloneDeep(target) {
if (!target || typeof target !== 'object') {
return target;
}
if (target instanceof Date) {
return new Date(target);
}
if (Array.isArray(target)) {
return target.map(cloneDeep);
}
return Object.keys(target).reduce((props, key) => {
props[key] = cloneDeep(target[key]);
return props;
}, {});
}
class NrfFormService {
constructor() {
this.formGroup = new FormGroup({});
this.submit$ = new EventEmitter();
}
set entity(entity) {
this.privateEntity = entity;
this.formData = cloneDeep(entity);
}
get entity() {
return this.privateEntity;
}
}
NrfFormService.decorators = [
{ type: Injectable }
];
function newNrfFormService() {
return new NrfFormService();
}
const NRF_FORM_SERVICE_PROVIDER = {
provide: NrfFormService,
useFactory: newNrfFormService,
};
class NrfFormDirective {
constructor(templateRef, viewContainerRef, formService, renderer) {
this.templateRef = templateRef;
this.viewContainerRef = viewContainerRef;
this.formService = formService;
this.renderer = renderer;
if (!formService) {
this.formService = new NrfFormService();
}
}
set nrfEntity(entity) {
this.formService.entity = entity;
}
get nrfEntity() {
return this.formService.entity;
}
get formData() {
return this.formService.formData;
}
get formGroup() {
return this.formService.formGroup;
}
get nrfSubmit() {
return this.formService.submit$;
}
ngOnInit() {
if (!this.nrfEntity) {
this.nrfEntity = {};
}
this.renderView();
}
ngOnDestroy() {
this.nrfSubmit.complete();
}
renderView() {
if (this.templateRef && this.viewContainerRef) {
const embeddedViewRef = this.viewContainerRef.createEmbeddedView(this.templateRef, new NrfFormContext(this));
const formNative = embeddedViewRef.rootNodes[0];
this.renderer.listen(formNative, 'submit', event => this.formSubmitWrapper(event));
}
}
formSubmitWrapper($event) {
$event.preventDefault();
if (!this.formGroup.valid) {
return;
}
this.nrfSubmit.emit(new NrfSubmitData(this, $event));
}
}
NrfFormDirective.decorators = [
{ type: Directive, args: [{
selector: '[nrfForm]',
exportAs: 'nrfForm',
},] }
];
NrfFormDirective.ctorParameters = () => [
{ type: TemplateRef, decorators: [{ type: Optional }] },
{ type: ViewContainerRef, decorators: [{ type: Optional }] },
{ type: NrfFormService, decorators: [{ type: Optional }] },
{ type: Renderer2 }
];
NrfFormDirective.propDecorators = {
nrfEntity: [{ type: Input }],
nrfSubmit: [{ type: Output }],
formSubmitWrapper: [{ type: HostListener, args: ['submit', ['$event'],] }]
};
class NrfFormModule {
}
NrfFormModule.decorators = [
{ type: NgModule, args: [{
imports: [FormsModule, ReactiveFormsModule],
exports: [FormsModule, ReactiveFormsModule, NrfFormDirective],
declarations: [NrfFormDirective],
},] }
];
class NrfControlOptionsComponent {
constructor() {
this.disabled = null;
this.min = null;
this.max = null;
this.required = null;
this.email = null;
this.minLength = null;
this.maxLength = null;
this.pattern = null;
this.updateOn = null;
}
ngOnInit() {
this.controlOptions = this.generateControlOptions();
}
generateControlOptions() {
return {
validators: Object.keys(Validators)
.filter((key) => this[key])
.map((key) => Validators[key]),
updateOn: this.updateOn,
disabled: this.disabled,
};
}
}
NrfControlOptionsComponent.propDecorators = {
disabled: [{ type: Input, args: ['disabled',] }],
min: [{ type: Input, args: ['min',] }],
max: [{ type: Input, args: ['max',] }],
required: [{ type: Input, args: ['required',] }],
email: [{ type: Input, args: ['email',] }],
minLength: [{ type: Input, args: ['minLength',] }],
maxLength: [{ type: Input, args: ['maxLength',] }],
pattern: [{ type: Input, args: ['pattern',] }],
updateOn: [{ type: Input, args: ['updateOn',] }]
};
class NrfNestedControlContext {
constructor(formControl, formGroup, nrfNestedControl) {
this.formControl = formControl;
this.formGroup = formGroup;
this.nrfNestedControl = nrfNestedControl;
this.$implicit = formControl;
}
}
class NrfFormHierarchyService {
getNestedControl(rootFormGroup, fullPath) {
let parentControl = ((rootFormGroup.get(fullPath)));
if (!parentControl) {
const pathPieces = Array.isArray(fullPath) ? fullPath : fullPath.split('.');
parentControl = pathPieces.reduce(this.createFormGroupHierarchy, rootFormGroup);
}
if (parentControl instanceof FormControl) {
parentControl = parentControl.parent;
}
return parentControl;
}
createFormGroupHierarchy(parentControl, path, index, pathPieces) {
if (index === pathPieces.length - 1) {
return parentControl;
}
let control = ((parentControl.get(path)));
if (!control) {
const nextPath = pathPieces[index + 1] || path;
const isArray = nextPath && !isNaN(((nextPath)));
control = isArray ? new FormArray([]) : new FormGroup({});
}
if (parentControl instanceof FormGroup) {
parentControl.addControl(path, control);
}
else if (parentControl instanceof FormArray) {
parentControl.insert(parseInt(path, 10) || 0, control);
}
return control;
}
}
NrfFormHierarchyService.decorators = [
{ type: Injectable }
];
class NrfModelSetterService {
constructor() {
this.getTargetPropToSet = (obj, key, i, pathPieces) => {
let nextKey = pathPieces[i + 1];
const isLast = nextKey == null;
nextKey = nextKey || pathPieces['finalKey'];
const isArrayKey = this.isArrayKey(nextKey);
let prop = obj[key];
if (!prop) {
prop = isArrayKey ? [] : {};
obj[key] = prop;
}
else if (isLast) {
prop = isArrayKey ? [...prop] : Object.assign({}, prop);
obj[key] = prop;
}
return prop;
};
}
getValue(path, model, separator = '.') {
if (path == null || !model) {
return null;
}
try {
const pathPieces = this.generatePathPieces(path, separator);
return pathPieces.reduce(this.piecesReducer, model) || null;
}
catch (err) {
return null;
}
}
piecesReducer(obj, key) {
return key === '' ? obj.slice(-1)[0] : obj[key];
}
setValue(path, value, model, separator = '.') {
if (!(path && model)) {
return null;
}
try {
const pathPieces = this.generatePathPieces(path, separator);
const finalKey = pathPieces.pop();
(((pathPieces)))['finalKey'] = finalKey;
const targetProp = pathPieces.reduce(this.getTargetPropToSet, model) || null;
if (finalKey === '') {
targetProp.push(value);
}
else {
targetProp[finalKey] = value;
}
}
catch (err) {
console.error('NestedProps setValue error: ', err);
}
}
isArrayKey(key) {
return key === '' || !isNaN(parseInt(key, 10));
}
generatePathPieces(path, separator) {
return path
.replace('[', separator)
.replace(']', '')
.split(separator);
}
}
NrfModelSetterService.decorators = [
{ type: Injectable }
];
class NrfNestedControlDirective {
constructor(modelSetter, templateRef, viewContainerRef, nrfForm, nrfFormService, formHierarchy) {
this.modelSetter = modelSetter;
this.templateRef = templateRef;
this.viewContainerRef = viewContainerRef;
this.formHierarchy = formHierarchy;
this.isDestroyed = false;
this.ready$ = new ReplaySubject(1);
this.formOrService = nrfFormService || nrfForm;
}
ngOnInit() {
this.modelPath = this.getModelPathWithoutFirstPart();
this.modelPieces = this.modelPath && this.modelPath.split('.');
this.controlName = this.getControlName();
this.formControl = this.getFormControl();
this.registerToFormGroup();
this.subscribeToUpdateEntityValue();
this.showViewContent();
this.emitReadyState();
}
ngOnDestroy() {
this.isDestroyed = true;
this.ready$.complete();
if (this.parentFormGroup) {
this.removeFromParentFormGroup();
}
}
removeFromParentFormGroup() {
if (this.parentFormGroup instanceof FormGroup) {
this.parentFormGroup.removeControl(this.nrfModelName);
}
else {
const index = this.parentFormGroup.controls.findIndex((control) => this.formControl === control);
this.parentFormGroup.removeAt(index);
}
}
getModelPathWithoutFirstPart() {
const modelName = this.nrfModelName;
return modelName && modelName.substr(modelName.indexOf('.') + 1);
}
getControlName() {
const modelPieces = this.modelPieces;
return modelPieces && modelPieces[modelPieces.length - 1];
}
getNewFormControl() {
const disabled = this.controlOptions && this.controlOptions.disabled;
const value = this.getInitialValue();
return new FormControl({ value, disabled }, this.controlOptions);
}
getInitialValue() {
if (this.formOrService && this.modelPath) {
return this.modelSetter.getValue(this.modelPath, this.formOrService.formData);
}
return null;
}
showViewContent() {
const context = new NrfNestedControlContext(this.formControl, this.formOrService && this.formOrService.formGroup, this);
this.viewContainerRef.createEmbeddedView(this.templateRef, context);
}
registerToFormGroup() {
if (this.parentFormGroup) {
return;
}
this.parentFormGroup = this.getParentFormGroup();
if (this.parentFormGroup) {
if (this.parentFormGroup instanceof FormGroup) {
this.parentFormGroup.addControl(this.modelPath, this.formControl);
}
else {
const index = this.controlName;
this.parentFormGroup.insert(parseInt(index, 10), this.formControl);
}
}
}
getParentFormGroup() {
const rootFormGroup = this.formOrService && this.formOrService.formGroup;
if (!rootFormGroup || !this.modelPath) {
return null;
}
const formGroupPath = Array.from(this.modelPieces);
return this.formHierarchy.getNestedControl(rootFormGroup, formGroupPath);
}
getFormControl() {
const formGroup = this.getParentFormGroup();
let formControl = formGroup && this.nrfModelName && ((formGroup.get(this.nrfModelName)));
if (!formControl) {
formControl = this.getNewFormControl();
}
return formControl;
}
subscribeToUpdateEntityValue() {
this.formControl.valueChanges
.pipe(takeWhile(() => !this.isDestroyed))
.subscribe((newValue) => this.setModelValue(newValue));
}
setModelValue(newValue) {
if (this.formOrService && this.modelPath) {
return this.modelSetter.setValue(this.modelPath, newValue || '', this.formOrService.formData);
}
}
emitReadyState() {
this.ready$.next(this);
}
}
NrfNestedControlDirective.decorators = [
{ type: Directive, args: [{
selector: '[nrfNestedControl]',
exportAs: 'nrfNestedControl',
},] }
];
NrfNestedControlDirective.ctorParameters = () => [
{ type: NrfModelSetterService },
{ type: TemplateRef },
{ type: ViewContainerRef },
{ type: NrfFormDirective, decorators: [{ type: Optional }] },
{ type: NrfFormService, decorators: [{ type: Optional }] },
{ type: NrfFormHierarchyService }
];
NrfNestedControlDirective.propDecorators = {
nrfModelName: [{ type: Input, args: ['nrfNestedControl',] }],
controlOptions: [{ type: Input, args: ['nrfNestedControlControlOptions',] }],
ready$: [{ type: Output }]
};
class NrfModelModule {
}
NrfModelModule.decorators = [
{ type: NgModule, args: [{
imports: [
CommonModule,
],
providers: [
NrfModelSetterService,
NrfFormHierarchyService,
],
declarations: [
NrfNestedControlDirective,
],
exports: [
NrfNestedControlDirective,
],
},] }
];
class NrFormsModule {
}
NrFormsModule.decorators = [
{ type: NgModule, args: [{
exports: [
NrfFormModule,
NrfModelModule,
],
},] }
];
export { NrFormsModule, cloneDeep, NrfFormDirective, NrfFormContext, NrfSubmitData, NrfFormService, NRF_FORM_SERVICE_PROVIDER, NrfFormModule, NrfNestedControlDirective, NrfNestedControlContext, NrfModelSetterService, NrfControlOptionsComponent, NrfFormHierarchyService, NrfModelModule, newNrfFormService as ɵa };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViZGV2LXRvb2xzLW5nLW5lc3RlZC1yZWFjdGl2ZS1mb3Jtcy5qcy5tYXAiLCJzb3VyY2VzIjpbIm5nOi8vQHdlYmRldi10b29scy9uZy1uZXN0ZWQtcmVhY3RpdmUtZm9ybXMvbGliL2Zvcm0vZm9ybS1jb250ZXh0LmNsYXNzLnRzIiwibmc6Ly9Ad2ViZGV2LXRvb2xzL25nLW5lc3RlZC1yZWFjdGl2ZS1mb3Jtcy9saWIvZm9ybS9mb3JtLXN1Ym1pdC1kYXRhLmNsYXNzLnRzIiwibmc6Ly9Ad2ViZGV2LXRvb2xzL25nLW5lc3RlZC1yZWFjdGl2ZS1mb3Jtcy9saWIvdXRpbHMvY2xvbmUtZGVlcC50cyIsIm5nOi8vQHdlYmRldi10b29scy9uZy1uZXN0ZWQtcmVhY3RpdmUtZm9ybXMvbGliL2Zvcm0vZm9ybS5zZXJ2aWNlLnRzIiwibmc6Ly9Ad2ViZGV2LXRvb2xzL25nLW5lc3RlZC1yZWFjdGl2ZS1mb3Jtcy9saWIvZm9ybS9mb3JtLmRpcmVjdGl2ZS50cyIsIm5nOi8vQHdlYmRldi10b29scy9uZy1uZXN0ZWQtcmVhY3RpdmUtZm9ybXMvbGliL2Zvcm0vZm9ybS5tb2R1bGUudHMiLCJuZzovL0B3ZWJkZXYtdG9vbHMvbmctbmVzdGVkLXJlYWN0aXZlLWZvcm1zL2xpYi9uZXN0ZWQtY29udHJvbC9jb250cm9sLW9wdGlvbnMuY29tcG9uZW50LnRzIiwibmc6Ly9Ad2ViZGV2LXRvb2xzL25nLW5lc3RlZC1yZWFjdGl2ZS1mb3Jtcy9saWIvbmVzdGVkLWNvbnRyb2wvbmVzdGVkLWNvbnRyb2wtY29udGV4dC5jbGFzcy50cyIsIm5nOi8vQHdlYmRldi10b29scy9uZy1uZXN0ZWQtcmVhY3RpdmUtZm9ybXMvbGliL25lc3RlZC1jb250cm9sL3NlcnZpY2VzL2Zvcm0taGllcmFyY2h5LnNlcnZpY2UudHMiLCJuZzovL0B3ZWJkZXYtdG9vbHMvbmctbmVzdGVkLXJlYWN0aXZlLWZvcm1zL2xpYi9uZXN0ZWQtY29udHJvbC9zZXJ2aWNlcy9tb2RlbC1zZXR0ZXIuc2VydmljZS50cyIsIm5nOi8vQHdlYmRldi10b29scy9uZy1uZXN0ZWQtcmVhY3RpdmUtZm9ybXMvbGliL25lc3RlZC1jb250cm9sL25lc3RlZC1jb250cm9sLmRpcmVjdGl2ZS50cyIsIm5nOi8vQHdlYmRldi10b29scy9uZy1uZXN0ZWQtcmVhY3RpdmUtZm9ybXMvbGliL25lc3RlZC1jb250cm9sL25lc3RlZC1jb250cm9sLm1vZHVsZS50cyIsIm5nOi8vQHdlYmRldi10b29scy9uZy1uZXN0ZWQtcmVhY3RpdmUtZm9ybXMvbGliL2Zvcm1zLm1vZHVsZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBGb3JtR3JvdXAgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5cbmltcG9ydCB7IE5yZkZvcm1EaXJlY3RpdmUgfSBmcm9tICcuL2Zvcm0uZGlyZWN0aXZlJztcblxuZXhwb3J0IGNsYXNzIE5yZkZvcm1Db250ZXh0IHtcbiAgJGltcGxpY2l0OiBOcmZGb3JtRGlyZWN0aXZlO1xuICBmb3JtR3JvdXA6IEZvcm1Hcm91cDtcblxuICBjb25zdHJ1Y3RvcihwdWJsaWMgbnJmRm9ybTogTnJmRm9ybURpcmVjdGl2ZSkge1xuICAgIHRoaXMuJGltcGxpY2l0ID0gbnJmRm9ybTtcbiAgICB0aGlzLmZvcm1Hcm91cCA9IG5yZkZvcm0uZm9ybUdyb3VwO1xuICB9XG59XG4iLCJpbXBvcnQgeyBGb3JtR3JvdXAgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5cbmltcG9ydCB7IE5yZkZvcm1EaXJlY3RpdmUgfSBmcm9tICcuL2Zvcm0uZGlyZWN0aXZlJztcblxuZXhwb3J0IGNsYXNzIE5yZlN1Ym1pdERhdGEge1xuICBucmZGb3JtOiBOcmZGb3JtRGlyZWN0aXZlO1xuICBmb3JtRGF0YTogYW55O1xuICBlbnRpdHk6IGFueTtcbiAgZm9ybUdyb3VwOiBGb3JtR3JvdXA7XG4gIGV2ZW50OiBFdmVudDtcblxuICBjb25zdHJ1Y3RvcihucmZGb3JtOiBOcmZGb3JtRGlyZWN0aXZlLCAkZXZlbnQ6IEV2ZW50KSB7XG4gICAgdGhpcy5ucmZGb3JtID0gbnJmRm9ybTtcbiAgICB0aGlzLmV2ZW50ID0gJGV2ZW50O1xuICAgIHRoaXMuZm9ybURhdGEgPSBucmZGb3JtLmZvcm1EYXRhO1xuICAgIHRoaXMuZW50aXR5ID0gbnJmRm9ybS5ucmZFbnRpdHk7XG4gICAgdGhpcy5mb3JtR3JvdXAgPSBucmZGb3JtLmZvcm1Hcm91cDtcbiAgfVxufVxuIiwiZXhwb3J0IGZ1bmN0aW9uIGNsb25lRGVlcCh0YXJnZXQ6IGFueSB8IGFueVtdKTogYW55IHtcbiAgaWYgKCF0YXJnZXQgfHwgdHlwZW9mIHRhcmdldCAhPT0gJ29iamVjdCcpIHtcbiAgICByZXR1cm4gdGFyZ2V0O1xuICB9XG5cbiAgaWYgKHRhcmdldCBpbnN0YW5jZW9mIERhdGUpIHtcbiAgICByZXR1cm4gbmV3IERhdGUodGFyZ2V0KTtcbiAgfVxuXG4gIGlmIChBcnJheS5pc0FycmF5KHRhcmdldCkpIHtcbiAgICByZXR1cm4gdGFyZ2V0Lm1hcChjbG9uZURlZXApO1xuICB9XG5cbiAgcmV0dXJuIE9iamVjdC5rZXlzKHRhcmdldCkucmVkdWNlKFxuICAgIChwcm9wcywga2V5KSA9PiB7XG4gICAgICBwcm9wc1trZXldID0gY2xvbmVEZWVwKHRhcmdldFtrZXldKTtcbiAgICAgIHJldHVybiBwcm9wcztcbiAgICB9LFxuICAgIHt9LFxuICApO1xufVxuIiwiaW1wb3J0IHsgRXZlbnRFbWl0dGVyLCBJbmplY3RhYmxlLCBQcm92aWRlciB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybUdyb3VwIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuXG5pbXBvcnQgeyBjbG9uZURlZXAgfSBmcm9tICcuLi91dGlscy9jbG9uZS1kZWVwJztcbmltcG9ydCB7IE5yZlN1Ym1pdERhdGEgfSBmcm9tICcuL2Zvcm0tc3VibWl0LWRhdGEuY2xhc3MnO1xuXG4vKiB0c2xpbnQ6ZGlzYWJsZSB0ZXItcGFkZGVkLWJsb2NrcyAqL1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgTnJmRm9ybVNlcnZpY2Uge1xuICAvKipcbiAgICogRm9ybSBncm91cCB3aWxsIGhvbGQgYWxsIGlucHV0cyB3aXRoaW4gdGhpcyBmb3JtLlxuICAgKlxuICAgKiBFdmVyeSBpbnB1dCBzaG91bGQgcmVnaXN0ZXIgaXRzZWxmIHRvIHRoaXMgZm9ybSBncm91cC5cbiAgICpcbiAgICogVGhlIGRhdGEgaW4gdGhpcyBmb3JtIGdyb3VwIHdpbGwgbm90IGJlIHNlbnQgdG8gYmFja2VuZCwganVzdCBmb3JtIHZhbGlkYXRpb25zIGFuZCBpbnB1dCBtYW5hZ2VtZW50LlxuICAgKi9cbiAgcmVhZG9ubHkgZm9ybUdyb3VwOiBGb3JtR3JvdXAgPSBuZXcgRm9ybUdyb3VwKHt9KTtcblxuICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6dmFyaWFibGUtbmFtZVxuICBwcml2YXRlIHByaXZhdGVFbnRpdHk6IGFueTtcblxuICBzZXQgZW50aXR5KGVudGl0eTogYW55KSB7XG4gICAgdGhpcy5wcml2YXRlRW50aXR5ID0gZW50aXR5O1xuICAgIHRoaXMuZm9ybURhdGEgPSBjbG9uZURlZXAoZW50aXR5KTsgLy8gVE9ETyBtZXJnZSB3aXRoIGV4aXN0ZW50IGZvcm1EYXRhXG4gIH1cbiAgZ2V0IGVudGl0eSgpIHtcbiAgICByZXR1cm4gdGhpcy5wcml2YXRlRW50aXR5O1xuICB9XG5cbiAgLyoqXG4gICAqIFJlcHJlc2VudHMgdGhlIGRhdGEgaW5wdXR0ZWQgYnkgdGhlIHVzZXIgb24gdGhlIGZpZWxkc1xuICAgKi9cbiAgZm9ybURhdGE6IGFueTtcblxuICAvKipcbiAgICogSW50ZXJuYWwgZW1pdHRlciB0byBoYW5kbGUgZm9ybSBzdWJtaXRcbiAgICovXG4gIHJlYWRvbmx5IHN1Ym1pdCQgPSBuZXcgRXZlbnRFbWl0dGVyPE5yZlN1Ym1pdERhdGE+KCk7XG59XG5cbi8qKlxuICogQGlnbm9yZVxuICovXG5leHBvcnQgZnVuY3Rpb24gbmV3TnJmRm9ybVNlcnZpY2UoKSB7XG4gIHJldHVybiBuZXcgTnJmRm9ybVNlcnZpY2UoKTtcbn1cblxuLyoqXG4gKiBVc2UgdGhpcyB0byBwcm92aWRlIGZvcm0tc2VydmljZSB0byBDb21wb25lbnRzIHRoYXQgd3JhcHMgbnJmRm9ybSBhbmQgcHV0IGlucHV0cyBpbnNpZGUgPG5nLWNvbnRlbnQ+XG4gKi9cbmV4cG9ydCBjb25zdCBOUkZfRk9STV9TRVJWSUNFX1BST1ZJREVSOiBQcm92aWRlciA9IHtcbiAgcHJvdmlkZTogTnJmRm9ybVNlcnZpY2UsXG4gIHVzZUZhY3Rvcnk6IG5ld05yZkZvcm1TZXJ2aWNlLFxufTtcbiIsImltcG9ydCB7XG4gIERpcmVjdGl2ZSxcbiAgRXZlbnRFbWl0dGVyLFxuICBIb3N0TGlzdGVuZXIsXG4gIElucHV0LFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgT3B0aW9uYWwsXG4gIE91dHB1dCxcbiAgUmVuZGVyZXIyLFxuICBUZW1wbGF0ZVJlZixcbiAgVmlld0NvbnRhaW5lclJlZixcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBGb3JtR3JvdXAgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5cbmltcG9ydCB7IE5yZkZvcm1Db250ZXh0IH0gZnJvbSAnLi9mb3JtLWNvbnRleHQuY2xhc3MnO1xuaW1wb3J0IHsgTnJmU3VibWl0RGF0YSB9IGZyb20gJy4vZm9ybS1zdWJtaXQtZGF0YS5jbGFzcyc7XG5pbXBvcnQgeyBOcmZGb3JtU2VydmljZSB9IGZyb20gJy4vZm9ybS5zZXJ2aWNlJztcblxuLyogdHNsaW50OmRpc2FibGU6IHRlci1wYWRkZWQtYmxvY2tzICovXG4vKipcbiAqIEEgY29tcG9uZW50IHRvIGFic3RyYWN0IHRoZSBmb3JtIGltcGxlbWVudGF0aW9uXG4gKlxuICogSXQgaG9sZHMgdGhlIHZhbGlkYXRpb24gYW5kIHRoZSBzdWJtaXQgbG9naWNcbiAqXG4gKiBAZXhhbXBsZVxuICogPGZvcm0gbnJmRm9ybSAobnJmU3VibWl0KT1cImFDYWxsYmFjaygkZXZlbnQpXCI+XG4gKiAgLy8gSW5wdXRzXG4gKiA8L2Zvcm0+XG4gKi9cbkBEaXJlY3RpdmUoe1xuICBzZWxlY3RvcjogJ1tucmZGb3JtXScsXG4gIGV4cG9ydEFzOiAnbnJmRm9ybScsXG59KVxuZXhwb3J0IGNsYXNzIE5yZkZvcm1EaXJlY3RpdmUgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XG4gIC8qKlxuICAgKiBAaWdub3JlXG4gICAqL1xuICBjb25zdHJ1Y3RvcihcbiAgICBAT3B0aW9uYWwoKSBwcml2YXRlIHJlYWRvbmx5IHRlbXBsYXRlUmVmOiBUZW1wbGF0ZVJlZjxhbnk+LFxuICAgIEBPcHRpb25hbCgpIHByaXZhdGUgcmVhZG9ubHkgdmlld0NvbnRhaW5lclJlZjogVmlld0NvbnRhaW5lclJlZixcbiAgICBAT3B0aW9uYWwoKSBwcml2YXRlIHJlYWRvbmx5IGZvcm1TZXJ2aWNlOiBOcmZGb3JtU2VydmljZSxcbiAgICBwcml2YXRlIHJlYWRvbmx5IHJlbmRlcmVyOiBSZW5kZXJlcjIsXG4gICkge1xuICAgIGlmICghZm9ybVNlcnZpY2UpIHtcbiAgICAgIHRoaXMuZm9ybVNlcnZpY2UgPSBuZXcgTnJmRm9ybVNlcnZpY2UoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVwcmVzZW50cyBhbiBFbnRpdHkgTW9kZWwgdGhhdCBjb21lcyBmcm9tIERhdGFiYXNlXG4gICAqL1xuICBASW5wdXQoKVxuICBzZXQgbnJmRW50aXR5KGVudGl0eTogYW55KSB7XG4gICAgdGhpcy5mb3JtU2VydmljZS5lbnRpdHkgPSBlbnRpdHk7XG4gIH1cbiAgZ2V0IG5yZkVudGl0eSgpOiBhbnkge1xuICAgIHJldHVybiB0aGlzLmZvcm1TZXJ2aWNlLmVudGl0eTtcbiAgfVxuXG4gIGdldCBmb3JtRGF0YSgpOiBhbnkge1xuICAgIHJldHVybiB0aGlzLmZvcm1TZXJ2aWNlLmZvcm1EYXRhO1xuICB9XG5cbiAgZ2V0IGZvcm1Hcm91cCgpOiBGb3JtR3JvdXAge1xuICAgIHJldHVybiB0aGlzLmZvcm1TZXJ2aWNlLmZvcm1Hcm91cDtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGZ1bmN0aW9uIHRoYXQgd2lsbCBiZSBjYWxsZWQgd2hlbiB0aGUgZm9ybSBpcyB2YWxpZCBhbmQgYSBzdWJtaXQgZXZlbnQgaXMgdHJpZ2dlcmVkXG4gICAqIGJ5IGEgYnV0dG9uIGNsaWNrIG9yIHByb2dyYW1tYXRpY2FsbHkuXG4gICAqL1xuICBAT3V0cHV0KClcbiAgZ2V0IG5yZlN1Ym1pdCgpOiBFdmVudEVtaXR0ZXI8TnJmU3VibWl0RGF0YT4ge1xuICAgIHJldHVybiB0aGlzLmZvcm1TZXJ2aWNlLnN1Ym1pdCQ7XG4gIH1cblxuXG4gIC8qKlxuICAgKiBJbml0IGFuIGVtcHR5IG5yZkVudGl0eSwgaW4gY2FzZSBub25lIHdoZXJlIHByb3ZpZGVkLlxuICAgKi9cbiAgbmdPbkluaXQoKSB7XG4gICAgaWYgKCF0aGlzLm5yZkVudGl0eSkge1xuICAgICAgdGhpcy5ucmZFbnRpdHkgPSB7fTtcbiAgICB9XG5cbiAgICB0aGlzLnJlbmRlclZpZXcoKTtcbiAgfVxuXG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgdGhpcy5ucmZTdWJtaXQuY29tcGxldGUoKTtcbiAgfVxuXG5cbiAgcHJpdmF0ZSByZW5kZXJWaWV3KCkge1xuICAgIGlmICh0aGlzLnRlbXBsYXRlUmVmICYmIHRoaXMudmlld0NvbnRhaW5lclJlZikge1xuICAgICAgY29uc3QgZW1iZWRkZWRWaWV3UmVmID0gdGhpcy52aWV3Q29udGFpbmVyUmVmLmNyZWF0ZUVtYmVkZGVkVmlldyh0aGlzLnRlbXBsYXRlUmVmLCBuZXcgTnJmRm9ybUNvbnRleHQodGhpcykpO1xuICAgICAgY29uc3QgZm9ybU5hdGl2ZSA9IGVtYmVkZGVkVmlld1JlZi5yb290Tm9kZXNbMF07XG4gICAgICB0aGlzLnJlbmRlcmVyLmxpc3Rlbihmb3JtTmF0aXZlLCAnc3VibWl0JywgZXZlbnQgPT4gdGhpcy5mb3JtU3VibWl0V3JhcHBlcihldmVudCkpO1xuICAgIH1cbiAgfVxuXG5cbiAgLyoqXG4gICAqICMgU2hvdWxkIG5vdCBiZSBjYWxsZWQgZGlyZWN0bHkhXG4gICAqIFRoaXMgbWV0aG9kIHdyYXBzIHRoZSBmb3JtIHZhbGlkYXRpb24gYW5kIGNhbGwgW25yZlN1Ym1pdF17QGxpbmsgTnJmRm9ybURpcmVjdGl2ZSNucmZTdWJtaXR9XG4gICAqL1xuICBASG9zdExpc3RlbmVyKCdzdWJtaXQnLCBbJyRldmVudCddKVxuICBmb3JtU3VibWl0V3JhcHBlcigkZXZlbnQ6IEV2ZW50KSB7XG4gICAgJGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICBpZiAoIXRoaXMuZm9ybUdyb3VwLnZhbGlkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5ucmZTdWJtaXQuZW1pdChuZXcgTnJmU3VibWl0RGF0YSh0aGlzLCAkZXZlbnQpKTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgTmdNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZvcm1zTW9kdWxlLCBSZWFjdGl2ZUZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuXG5pbXBvcnQgeyBOcmZGb3JtQ29udGV4dCB9IGZyb20gJy4vZm9ybS1jb250ZXh0LmNsYXNzJztcbmltcG9ydCB7IE5yZlN1Ym1pdERhdGEgfSBmcm9tICcuL2Zvcm0tc3VibWl0LWRhdGEuY2xhc3MnO1xuaW1wb3J0IHsgTnJmRm9ybURpcmVjdGl2ZSB9IGZyb20gJy4vZm9ybS5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgTlJGX0ZPUk1fU0VSVklDRV9QUk9WSURFUiwgTnJmRm9ybVNlcnZpY2UgfSBmcm9tICcuL2Zvcm0uc2VydmljZSc7XG5cbmV4cG9ydCB7IE5yZkZvcm1EaXJlY3RpdmUsIE5yZkZvcm1Db250ZXh0LCBOcmZTdWJtaXREYXRhLCBOcmZGb3JtU2VydmljZSwgTlJGX0ZPUk1fU0VSVklDRV9QUk9WSURFUiB9O1xuXG4vKiB0c2xpbnQ6ZGlzYWJsZTogdGVyLXBhZGRlZC1ibG9ja3MgKi9cbi8qKlxuICogVGhpcyBtb2R1bGUgb25seSBoYW5kbGUgZm9ybSBBYnN0cmFjdGlvbiBhbmQgc3VibWl0IGhhbmRsZXJcbiAqIE5vIGlucHV0cyBhcmUgcHJvdmlkZWQgYnkgdGhpcyBtb2R1bGUuXG4gKi9cbkBOZ01vZHVsZSh7XG4gIGltcG9ydHM6IFtGb3Jtc01vZHVsZSwgUmVhY3RpdmVGb3Jtc01vZHVsZV0sXG4gIGV4cG9ydHM6IFtGb3Jtc01vZHVsZSwgUmVhY3RpdmVGb3Jtc01vZHVsZSwgTnJmRm9ybURpcmVjdGl2ZV0sXG4gIGRlY2xhcmF0aW9uczogW05yZkZvcm1EaXJlY3RpdmVdLFxufSlcbmV4cG9ydCBjbGFzcyBOcmZGb3JtTW9kdWxlIHt9XG4iLCJpbXBvcnQgeyBJbnB1dCwgT25Jbml0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2xPcHRpb25zLCBWYWxpZGF0b3JzIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuXG4vKiB0c2xpbnQ6ZGlzYWJsZTogdGVyLXBhZGRlZC1ibG9ja3MgKi9cblxuZXhwb3J0IGludGVyZmFjZSBOcmZDb250cm9sT3B0aW9ucyBleHRlbmRzIEFic3RyYWN0Q29udHJvbE9wdGlvbnMge1xuICBkaXNhYmxlZDogYm9vbGVhbjtcbn1cblxuLy8gdHNsaW50OmRpc2FibGUgbm8taW5wdXQtcmVuYW1lXG5cbi8qKlxuICogSW5wdXQgd3JhcHBlcnMgY29tcG9uZW50cyBzaG91bGQgZXh0ZW5kcyB0aGlzIGNsYXNzIHRvIHBhc3MgY29uc3RyYWludHMgZG93bndhcmRzXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBOcmZDb250cm9sT3B0aW9uc0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIC8qKlxuICAgKiBBIGxpc3Qgb2YgVmFsaWRhdG9ycyB0byB2YWxpZGF0ZSB0aGUgaW5wdXQgYW5kIHRoZSB1cGRhdGUtb24gc3RyYXRlZ3lcbiAgICovXG4gIGNvbnRyb2xPcHRpb25zOiBOcmZDb250cm9sT3B0aW9ucztcblxuICAvKipcbiAgICogU2V0cyB0aGlzIGlucHV0IHRvIHJlYWRvbmx5IGFuZCBibG9jayBhbnkgY2hhbmdlc1xuICAgKi9cbiAgQElucHV0KCdkaXNhYmxlZCcpIGRpc2FibGVkOiBib29sZWFuID0gbnVsbDtcblxuICAvKipcbiAgICogRGVmaW5lIHRoZSBsb3dlc3QgbnVtYmVyIHZhbHVlIHRoYXQgdGhpcyBpbnB1dCBzaG91bGQgYWNjZXB0XG4gICAqL1xuICBASW5wdXQoJ21pbicpIG1pbjogc3RyaW5nIHwgbnVtYmVyID0gbnVsbDtcblxuICAvKipcbiAgICogRGVmaW5lIHRoZSBtYXhpbXVtIG51bWJlciB2YWx1ZSB0aGF0IHRoaXMgaW5wdXQgc2hvdWxkIGFjY2VwdFxuICAgKi9cbiAgQElucHV0KCdtYXgnKSBtYXg6IHN0cmluZyB8IG51bWJlciA9IG51bGw7XG5cbiAgLyoqXG4gICAqIFNldCB0aGlzIGlucHV0IGFzIHJlcXVpcmVkIGFuZCBmYWlscyB3aGVuIGVtcHR5XG4gICAqL1xuICBASW5wdXQoJ3JlcXVpcmVkJykgcmVxdWlyZWQ6IGJvb2xlYW4gPSBudWxsO1xuXG4gIC8vIEBJbnB1dCgnUmVxdWlyZWRUcnVlJykgcmVxdWlyZWRUcnVlOiBzdHJpbmcgPSBudWxsO1xuXG4gIC8qKlxuICAgKiBTZXQgdGhpcyBpbnB1dCBhcyBhbiBlLW1haWwgYW5kIHZhbGlkYXRlcyB0aGUgZS1tYWlsIHBhdHRlclxuICAgKi9cbiAgQElucHV0KCdlbWFpbCcpIGVtYWlsOiBib29sZWFuID0gbnVsbDtcblxuICAvKipcbiAgICogRGVmaW5lIHRoZSBtaW5pbXVtIGNoYXJhY3RlcnMgcXVhbnRpdHkgdGhpcyBpbnB1dCBzaG91bGQgYWNjZXB0XG4gICAqL1xuICBASW5wdXQoJ21pbkxlbmd0aCcpIG1pbkxlbmd0aDogc3RyaW5nIHwgbnVtYmVyID0gbnVsbDtcblxuICAvKipcbiAgICogRGVmaW5lIHRoZSBtYXhpbXVtIGNoYXJhY3RlcnMgcXVhbnRpdHkgdGhpcyBpbnB1dCBzaG91bGQgYWNjZXB0XG4gICAqL1xuICBASW5wdXQoJ21heExlbmd0aCcpIG1heExlbmd0aDogc3RyaW5nIHwgbnVtYmVyID0gbnVsbDtcblxuICAvKipcbiAgICogU2V0IGEgUmVndWxhciBFeHByZXNzaW9uIHRvIG1hdGNoIHRoZSBpbnB1dCB2YWx1ZSBhZ2FpbnN0IGFuZCBmYWlscyBpZiBub3QgbWF0Y2hcbiAgICovXG4gIEBJbnB1dCgncGF0dGVybicpIHBhdHRlcm46IHN0cmluZyB8IFJlZ0V4cCA9IG51bGw7XG5cbiAgLyoqXG4gICAqIFRoZSBldmVudCBuYW1lIGZvciBjb250cm9sIHRvIHVwZGF0ZSB1cG9uLlxuICAgKi9cbiAgQElucHV0KCd1cGRhdGVPbicpIHVwZGF0ZU9uOiAnY2hhbmdlJyB8ICdibHVyJyB8ICdzdWJtaXQnID0gbnVsbDtcblxuICAvKipcbiAgICogQ2FjaGUgdGhlIHZhbGlkYXRvcnMgdG8gZW5oYW5jZSB0aGUgcGVyZm9ybWFuY2VcbiAgICovXG4gIG5nT25Jbml0KCkge1xuICAgIHRoaXMuY29udHJvbE9wdGlvbnMgPSB0aGlzLmdlbmVyYXRlQ29udHJvbE9wdGlvbnMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSB0aGUgY29udHJvbCBvcHRpb25zIGJhc2VkIG9uIHRoZSBwcm9wZXJ0aWVzIHNldCBpbiB0aGlzIGNvbXBvbmVudFxuICAgKi9cbiAgZ2VuZXJhdGVDb250cm9sT3B0aW9ucygpOiBOcmZDb250cm9sT3B0aW9ucyB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHZhbGlkYXRvcnM6IE9iamVjdC5rZXlzKFZhbGlkYXRvcnMpXG4gICAgICAgIC5maWx0ZXIoKGtleSkgPT4gdGhpc1trZXldKVxuICAgICAgICAubWFwKChrZXkpID0+IFZhbGlkYXRvcnNba2V5XSksXG4gICAgICB1cGRhdGVPbjogdGhpcy51cGRhdGVPbixcbiAgICAgIGRpc2FibGVkOiB0aGlzLmRpc2FibGVkLFxuICAgIH07XG4gIH1cbn1cbiIsImltcG9ydCB7IEZvcm1Db250cm9sLCBGb3JtR3JvdXAgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5cbmltcG9ydCB7IE5yZk5lc3RlZENvbnRyb2xEaXJlY3RpdmUgfSBmcm9tICcuL25lc3RlZC1jb250cm9sLmRpcmVjdGl2ZSc7XG5cbmV4cG9ydCBjbGFzcyBOcmZOZXN0ZWRDb250cm9sQ29udGV4dCB7XG4gICRpbXBsaWNpdDogRm9ybUNvbnRyb2w7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIGZvcm1Db250cm9sOiBGb3JtQ29udHJvbCxcbiAgICBwdWJsaWMgZm9ybUdyb3VwOiBGb3JtR3JvdXAsXG4gICAgcHVibGljIG5yZk5lc3RlZENvbnRyb2w6IE5yZk5lc3RlZENvbnRyb2xEaXJlY3RpdmUsXG4gICkge1xuICAgIHRoaXMuJGltcGxpY2l0ID0gZm9ybUNvbnRyb2w7XG4gIH1cbn1cbiIsImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZvcm1BcnJheSwgRm9ybUNvbnRyb2wsIEZvcm1Hcm91cCB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcblxuLyogdHNsaW50OmRpc2FibGUgdGVyLXBhZGRlZC1ibG9ja3MgKi9cblxuQEluamVjdGFibGUoKVxuLyoqXG4gKiBDb250cm9scyB0aGUgSGllcmFyY2h5IG9mIEZvcm1Hcm91cHMgYW5kIEZvcm1BcnJheXNcbiAqL1xuZXhwb3J0IGNsYXNzIE5yZkZvcm1IaWVyYXJjaHlTZXJ2aWNlIHtcbiAgLyoqXG4gICAqIEdldCBhIG5lc3RlZCBjb250cm9sIGlmIGl0IGV4aXN0cyBvciBjcmVhdGUgdGhlIGl0cyBuZWNlc3NhcnkgaGllcmFyY2h5XG4gICAqXG4gICAqIEBwYXJhbSBmdWxsUGF0aCBEb3Qgbm90YXRpb24gcGF0aCBvZiB0aGUgZGVzaXJlZCBjb250cm9sLCBpbmNsdWRpbmcgdGhlIGxhc3QgcGFydCwgdGhhdCBpcyB0aGUgdmFsdWUsIG5vdCB0aGUgZ3JvdXAuXG4gICAqL1xuICBnZXROZXN0ZWRDb250cm9sKHJvb3RGb3JtR3JvdXA6IEZvcm1Hcm91cCB8IEZvcm1BcnJheSwgZnVsbFBhdGg6IHN0cmluZyB8IHN0cmluZ1tdKTogRm9ybUdyb3VwIHwgRm9ybUFycmF5IHtcbiAgICBsZXQgcGFyZW50Q29udHJvbCA9IDxGb3JtR3JvdXAgfCBGb3JtQXJyYXk+cm9vdEZvcm1Hcm91cC5nZXQoZnVsbFBhdGgpO1xuXG4gICAgaWYgKCFwYXJlbnRDb250cm9sKSB7XG4gICAgICBjb25zdCBwYXRoUGllY2VzID0gQXJyYXkuaXNBcnJheShmdWxsUGF0aCkgPyBmdWxsUGF0aCA6IGZ1bGxQYXRoLnNwbGl0KCcuJyk7XG4gICAgICBwYXJlbnRDb250cm9sID0gcGF0aFBpZWNlcy5yZWR1Y2U8Rm9ybUdyb3VwIHwgRm9ybUFycmF5Pih0aGlzLmNyZWF0ZUZvcm1Hcm91cEhpZXJhcmNoeSwgcm9vdEZvcm1Hcm91cCk7XG4gICAgfVxuXG4gICAgaWYgKHBhcmVudENvbnRyb2wgaW5zdGFuY2VvZiBGb3JtQ29udHJvbCkge1xuICAgICAgcGFyZW50Q29udHJvbCA9IHBhcmVudENvbnRyb2wucGFyZW50O1xuICAgIH1cblxuICAgIHJldHVybiBwYXJlbnRDb250cm9sO1xuICB9XG5cbiAgLyoqXG4gICAqIEl0ZXJhdGUgb3ZlciBhbGwgcGF0aCBwaWVjZXMgY3JlYXRpbmcgdGhlIG5lZWRlZCBjb250cm9scyBpZiB0aGV5IGRvIG5vdCBleGlzdHMuXG4gICAqL1xuICBwcml2YXRlIGNyZWF0ZUZvcm1Hcm91cEhpZXJhcmNoeShcbiAgICBwYXJlbnRDb250cm9sOiBGb3JtR3JvdXAgfCBGb3JtQXJyYXksXG4gICAgcGF0aDogc3RyaW5nLFxuICAgIGluZGV4OiBudW1iZXIsXG4gICAgcGF0aFBpZWNlczogc3RyaW5nW10sXG4gICk6IEZvcm1Hcm91cCB8IEZvcm1BcnJheSB7XG4gICAgaWYgKGluZGV4ID09PSBwYXRoUGllY2VzLmxlbmd0aCAtIDEpIHtcbiAgICAgIHJldHVybiBwYXJlbnRDb250cm9sO1xuICAgIH1cblxuICAgIGxldCBjb250cm9sID0gPEZvcm1Hcm91cCB8IEZvcm1BcnJheT5wYXJlbnRDb250cm9sLmdldChwYXRoKTtcblxuICAgIGlmICghY29udHJvbCkge1xuICAgICAgY29uc3QgbmV4dFBhdGggPSBwYXRoUGllY2VzW2luZGV4ICsgMV0gfHwgcGF0aDtcblxuICAgICAgY29uc3QgaXNBcnJheSA9IG5leHRQYXRoICYmICFpc05hTig8YW55Pm5leHRQYXRoKTtcbiAgICAgIGNvbnRyb2wgPSBpc0FycmF5ID8gbmV3IEZvcm1BcnJheShbXSkgOiBuZXcgRm9ybUdyb3VwKHt9KTtcbiAgICB9XG5cbiAgICBpZiAocGFyZW50Q29udHJvbCBpbnN0YW5jZW9mIEZvcm1Hcm91cCkge1xuICAgICAgcGFyZW50Q29udHJvbC5hZGRDb250cm9sKHBhdGgsIGNvbnRyb2wpO1xuICAgIH0gZWxzZSBpZiAocGFyZW50Q29udHJvbCBpbnN0YW5jZW9mIEZvcm1BcnJheSkge1xuICAgICAgcGFyZW50Q29udHJvbC5pbnNlcnQocGFyc2VJbnQocGF0aCwgMTApIHx8IDAsIGNvbnRyb2wpO1xuICAgIH1cblxuICAgIHJldHVybiBjb250cm9sO1xuICB9XG59XG4iLCJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbi8qIHRzbGludDpkaXNhYmxlIHRlci1wYWRkZWQtYmxvY2tzICovXG5cbi8qKlxuICogQ2xhc3MgdG8gYWJzdHJhY3QgZ2V0IGFuZCBzZXQgdmFsdWVzIGZyb20gYW4gb2JqZWN0IG9yIGFuIGFycmF5XG4gKiB1c2luZyBkb3Qtbm90YXRpb24gc3RyaW5nIGFzIHRoZSBwYXRoIHRvIHRoZSBwcm9wZXJ0eVxuICpcbiAqL1xuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIE5yZk1vZGVsU2V0dGVyU2VydmljZSB7XG4gIC8qKlxuICAgKiBHZXQgYSB2YWx1ZSB1c2luZyBhIGRvdC1ub3RhdGlvbiBzdHJpbmcgdG8gZmluZCB0aGUgbmVzdGVkIHByb3BlcnR5XG4gICAqXG4gICAqIEBwYXJhbSBwYXRoIERvdCBub3RhdGlvbiBvZiB0aGUgdmFsdWUgdG8gYmUgZ2V0XG4gICAqIEBwYXJhbSBtb2RlbCBBbiBvYmplY3Qgb3IgYW4gQXJyYXlcbiAgICogQHBhcmFtIHNlcGFyYXRvciBBbiBvcHRpb25hbCBwYXJhbSB0byBzcGVjaWZ5IGEgZGlmZmVyZW50IHNlcGFyYXRvciwgZGVmYXVsdCAnLidcbiAgICpcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCBucmZFbnRpdHkgPSB7XG4gICAqICAgIHVzZXI6IHtcbiAgICogICAgICAgIG5hbWU6ICdKb2huIERvZSdcbiAgICogICAgfVxuICAgKiB9O1xuICAgKiBuZXN0ZWRQcm9wcy5nZXRWYWx1ZSgndXNlci5uYW1lJywgbnJmRW50aXR5KTtcbiAgICogLy8gPT4gJ0pvaG4gRG9lJ1xuICAgKlxuICAgKiBuZXN0ZWRQcm9wcy5nZXRWYWx1ZSgndXNlci5lbWFpbCcsIG5yZkVudGl0eSk7XG4gICAqIC8vID0+IG51bGxcbiAgICogYGBgXG4gICAqL1xuICBnZXRWYWx1ZShwYXRoOiBzdHJpbmcsIG1vZGVsOiBhbnkgfCBhbnlbXSwgc2VwYXJhdG9yID0gJy4nKTogYW55IHwgbnVsbCB7XG4gICAgaWYgKHBhdGggPT0gbnVsbCB8fCAhbW9kZWwpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYXRoUGllY2VzID0gdGhpcy5nZW5lcmF0ZVBhdGhQaWVjZXMocGF0aCwgc2VwYXJhdG9yKTtcbiAgICAgIHJldHVybiBwYXRoUGllY2VzLnJlZHVjZSh0aGlzLnBpZWNlc1JlZHVjZXIsIG1vZGVsKSB8fCBudWxsO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBpZ25vcmVcbiAgICpcbiAgICogUmV0dXJuIHRoZSB2YWx1ZSBhc3NvY2lhdGVkIHRvIHRoZSBnaXZlbiBrZXkuXG4gICAqXG4gICAqIElmIHRoZSBrZXkgaXMgZW1wdHksIHRoZSBsYXN0IGVsZW1lbnQgb2YgYW4gYXJyYXkgaXMgcmV0dXJuZWRcbiAgICovXG4gIHByaXZhdGUgcGllY2VzUmVkdWNlcihvYmo6IGFueVtdIHwgYW55LCBrZXk6IHN0cmluZyk6IGFueSB8IGFueVtdIHtcbiAgICByZXR1cm4ga2V5ID09PSAnJyA/IG9iai5zbGljZSgtMSlbMF0gOiBvYmpba2V5XTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgYSB2YWx1ZSB1c2luZyBhIGRvdC1ub3RhdGlvbiBzdHJpbmcuXG4gICAqXG4gICAqIElmIHRoZSBwcm9wZXJ0eSBkb2VzIG5vdCBleGlzdHMsIHRoZSBlbnRpcmUgcGF0aCB3aWxsIGJlIGNyZWF0ZWQuXG4gICAqXG4gICAqIEBwYXJhbSBwYXRoIERvdCBub3RhdGlvbiBvZiB0aGUgdmFsdWUgdG8gYmUgZ2V0XG4gICAqIEBwYXJhbSB2YWx1ZSBUaGUgdmFsdWUgdG8gYmUgc2V0XG4gICAqIEBwYXJhbSBtb2RlbCBBbiBvYmplY3Qgb3IgYW4gQXJyYXlcbiAgICogQHBhcmFtIHNlcGFyYXRvciBBbiBvcHRpb25hbCBwYXJhbSB0byBzcGVjaWZ5IGEgZGlmZmVyZW50IHNlcGFyYXRvciwgZGVmYXVsdCAnLidcbiAgICpcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBuZXN0ZWRQcm9wcy5zZXRWYWx1ZSgndXNlci5hZ2UnLCAzNSwgeyB1c2VyOiB7IG5hbWU6ICdKb2huIERvZScgfSB9KTtcbiAgICogYGBgXG4gICAqL1xuICBzZXRWYWx1ZShwYXRoOiBzdHJpbmcsIHZhbHVlOiBhbnksIG1vZGVsOiBvYmplY3QgfCBhbnlbXSwgc2VwYXJhdG9yID0gJy4nKTogdm9pZCB7XG4gICAgLy8gVE9ETyByZW1vdmUgdGhlIGVtcHR5IGtleSBmZWF0dXJlLCBmb3JjZSB1c2VycyB0byBkZWZpbmUgdGhlIGRlc2lyZWQgYXJyYXkga2V5XG4gICAgaWYgKCEocGF0aCAmJiBtb2RlbCkpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYXRoUGllY2VzID0gdGhpcy5nZW5lcmF0ZVBhdGhQaWVjZXMocGF0aCwgc2VwYXJhdG9yKTtcbiAgICAgIGNvbnN0IGZpbmFsS2V5ID0gcGF0aFBpZWNlcy5wb3AoKTtcbiAgICAgICg8YW55PnBhdGhQaWVjZXMpWydmaW5hbEtleSddID0gZmluYWxLZXk7XG5cbiAgICAgIGNvbnN0IHRhcmdldFByb3AgPSBwYXRoUGllY2VzLnJlZHVjZSh0aGlzLmdldFRhcmdldFByb3BUb1NldCwgbW9kZWwpIHx8IG51bGw7XG5cbiAgICAgIGlmIChmaW5hbEtleSA9PT0gJycpIHtcbiAgICAgICAgdGFyZ2V0UHJvcC5wdXNoKHZhbHVlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRhcmdldFByb3BbZmluYWxLZXldID0gdmFsdWU7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdOZXN0ZWRQcm9wcyBzZXRWYWx1ZSBlcnJvcjogJywgZXJyKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBmaW5hbCBwcm9wZXJ0eSBvZiB0aGUgZG90IG5vdGF0aW9uIHBhdGguXG4gICAqIFRoaXMgd2lsbCBiZSB0aGUgcHJvcGVydHkgdGhhdCB3aWxsIHJlY2VpdmUgdGhlIG5ldyB2YWx1ZVxuICAgKi9cbiAgcHJpdmF0ZSBnZXRUYXJnZXRQcm9wVG9TZXQgPSAob2JqOiBhbnksIGtleTogc3RyaW5nLCBpOiBudW1iZXIsIHBhdGhQaWVjZXM6IGFueSk6IGFueVtdIHwgYW55ID0+IHtcbiAgICBsZXQgbmV4dEtleSA9IHBhdGhQaWVjZXNbaSArIDFdO1xuICAgIGNvbnN0IGlzTGFzdCA9IG5leHRLZXkgPT0gbnVsbDtcblxuICAgIG5leHRLZXkgPSBuZXh0S2V5IHx8IHBhdGhQaWVjZXNbJ2ZpbmFsS2V5J107XG5cbiAgICBjb25zdCBpc0FycmF5S2V5ID0gdGhpcy5pc0FycmF5S2V5KG5leHRLZXkpO1xuICAgIGxldCBwcm9wID0gb2JqW2tleV07XG5cbiAgICBpZiAoIXByb3ApIHtcbiAgICAgIHByb3AgPSBpc0FycmF5S2V5ID8gW10gOiB7fTtcbiAgICAgIG9ialtrZXldID0gcHJvcDtcbiAgICB9IGVsc2UgaWYgKGlzTGFzdCkge1xuICAgICAgcHJvcCA9IGlzQXJyYXlLZXkgPyBbLi4ucHJvcF0gOiB7IC4uLnByb3AgfTtcbiAgICAgIG9ialtrZXldID0gcHJvcDtcbiAgICB9XG5cbiAgICByZXR1cm4gcHJvcDtcbiAgfTtcblxuICAvKipcbiAgICogQGlnbm9yZVxuICAgKiBJbnRlcm5hbCBmdW5jdGlvbiB0byBkZWZpbmUgaWYgYSBnaXZlbiBrZXkgaXMgZm9yIGFuIGFycmF5IG9yIGFuIG9iamVjdFxuICAgKi9cbiAgcHJpdmF0ZSBpc0FycmF5S2V5KGtleTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGtleSA9PT0gJycgfHwgIWlzTmFOKHBhcnNlSW50KGtleSwgMTApKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSB0aGUgZG90LW5vdGF0aW9uIHBhdGggYXMgYW4gQXJyYXkgdG8gaXRlcmF0ZSBvdmVyLlxuICAgKi9cbiAgcHJpdmF0ZSBnZW5lcmF0ZVBhdGhQaWVjZXMocGF0aDogc3RyaW5nLCBzZXBhcmF0b3I6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gcGF0aFxuICAgICAgLnJlcGxhY2UoJ1snLCBzZXBhcmF0b3IpXG4gICAgICAucmVwbGFjZSgnXScsICcnKVxuICAgICAgLnNwbGl0KHNlcGFyYXRvcik7XG4gIH1cbn1cbiIsImltcG9ydCB7IERpcmVjdGl2ZSwgSW5wdXQsIE9uRGVzdHJveSwgT25Jbml0LCBPcHRpb25hbCwgT3V0cHV0LCBUZW1wbGF0ZVJlZiwgVmlld0NvbnRhaW5lclJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybUFycmF5LCBGb3JtQ29udHJvbCwgRm9ybUdyb3VwIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuXG5pbXBvcnQgeyBSZXBsYXlTdWJqZWN0IH0gZnJvbSAncnhqcy9pbnRlcm5hbC9SZXBsYXlTdWJqZWN0JztcbmltcG9ydCB7IHRha2VXaGlsZSB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHsgTnJmRm9ybURpcmVjdGl2ZSB9IGZyb20gJy4uL2Zvcm0vZm9ybS5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgTnJmRm9ybVNlcnZpY2UgfSBmcm9tICcuLi9mb3JtL2Zvcm0uc2VydmljZSc7XG5pbXBvcnQgeyBOcmZDb250cm9sT3B0aW9ucyB9IGZyb20gJy4vY29udHJvbC1vcHRpb25zLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBOcmZOZXN0ZWRDb250cm9sQ29udGV4dCB9IGZyb20gJy4vbmVzdGVkLWNvbnRyb2wtY29udGV4dC5jbGFzcyc7XG5pbXBvcnQgeyBOcmZGb3JtSGllcmFyY2h5U2VydmljZSB9IGZyb20gJy4vc2VydmljZXMvZm9ybS1oaWVyYXJjaHkuc2VydmljZSc7XG5pbXBvcnQgeyBOcmZNb2RlbFNldHRlclNlcnZpY2UgfSBmcm9tICcuL3NlcnZpY2VzL21vZGVsLXNldHRlci5zZXJ2aWNlJztcblxuLyogdHNsaW50OmRpc2FibGUgdGVyLXBhZGRlZC1ibG9ja3MgKi9cblxuLyoqXG4gKiBUaGlzIGRpcmVjdGl2ZSBjb250cm9sIG5lc3RlZCBpbnB1dHMgYW5kIHNldHMgdmFsdWVzIG9uIHRoZSBPcmlnaW5hbCBNb2RlbCBzZXQgYXQge0BsaW5rIE5yZkZvcm1EaXJlY3RpdmUjbnJmRW50aXR5fVxuICpcbiAqICMjIyMgR2l2ZW4gYW4gbnJmRW50aXR5IG9uIHRoZSBjb250cm9sbGVyOlxuICogYGBgdHlwZXNjcmlwdFxuICogdGhpcy51c2VyTW9kZWwgPSB7XG4gKiAgICBmaXJzdE5hbWU6ICdKb2huJyxcbiAqICAgIGFkZHJlc3M6IHtcbiAqICAgICAgICBzdHJlZXQ6ICdDYXJuYWJ5IFN0cmVldCdcbiAqICAgIH1cbiAqIH07XG4gKiBgYGBcbiAqXG4gKiAjIyMjIFVzZSBpdCBvbiB0aGUgZm9ybVxuICogYGBgaHRtbFxuICogPGZvcm0gW25yZkVudGl0eV09XCJ1c2VyTW9kZWxcIj5cbiAqICAgPGRpdiBjbGFzcz1cImZvcm0tZ3JvdXBcIj5cbiAqICAgICAgPGxhYmVsIGZvcj1cIm5hbWVcIj5OYW1lOjwvbGFiZWw+XG4gKlxuICogICAgICA8ZGl2ICpucmZOZXN0ZWRDb250cm9sPVwiJ3VzZXJNb2RlbC5maXJzdE5hbWUnOyBsZXQgY29udHJvbD1mb3JtQ29udHJvbFwiPlxuICogICAgICAgIDxpbnB1dCBbZm9ybUNvbnRyb2xdPVwiY29udHJvbFwiIC8+XG4gKiAgICAgIDwvZGl2PlxuICogICA8L2Rpdj5cbiAqIDwvZm9ybT5cbiAqIGBgYFxuICovXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdbbnJmTmVzdGVkQ29udHJvbF0nLFxuICBleHBvcnRBczogJ25yZk5lc3RlZENvbnRyb2wnLFxufSlcbmV4cG9ydCBjbGFzcyBOcmZOZXN0ZWRDb250cm9sRGlyZWN0aXZlIGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICBpc0Rlc3Ryb3llZCA9IGZhbHNlO1xuICBwYXJlbnRGb3JtR3JvdXA6IEZvcm1Hcm91cCB8IEZvcm1BcnJheTtcbiAgZm9ybUNvbnRyb2w6IEZvcm1Db250cm9sO1xuXG4gIC8qKlxuICAgKiBVc2VkIHRvIHNldCBhbmQgZ2V0IHZhbHVlIG9uIHRoZSBlbnRpdHkgbW9kZWxcbiAgICovXG4gIG1vZGVsUGF0aDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBcnJheSBmcm9tIG1vZGVsIHBhdGggc3BsaXQgYnkgJy4nXG4gICAqL1xuICBwcml2YXRlIG1vZGVsUGllY2VzOiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogVGhlIGxhc3QgcGFydCBvZiB0aGUgZG90LW5vdGF0aW9uIHBhdGggcHJvdmlkZWQgb24gW25yZk1vZGVsTmFtZV17QGxpbmsgbnJmTW9kZWxOYW1lfSBwcm9wZXJ0eS5cbiAgICogQ2FuIGJlIHVzZWQgd2l0aCBmb3JtQ29udHJvbE5hbWUgcHJvcGVydHlcbiAgICovXG4gIGNvbnRyb2xOYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEhvbGRzIGFuIGluc3RhbmNlIG9mIGEgTnJmRm9ybSBvciBhIE5yZlNlcnZpY2UuXG4gICAqIElmIHRoZSBmb3JtIGlzIHdyYXBwZWQgaW5zaWRlIGEgZGlyZWN0aXZlIHdpdGggbmctY29udGVudCwgdGhlIE5yZkZvcm1TZXJ2aWNlIE1VU1QgYmUgcHJvdmlkZWQuXG4gICAqIE90aGVyd2lzZSB0aGUgbnJmRm9ybSB3aWxsIGJlIHVzZWQuXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGZvcm1PclNlcnZpY2U6IE5yZkZvcm1EaXJlY3RpdmUgfCBOcmZGb3JtU2VydmljZTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IG1vZGVsU2V0dGVyOiBOcmZNb2RlbFNldHRlclNlcnZpY2UsXG4gICAgcHJpdmF0ZSByZWFkb25seSB0ZW1wbGF0ZVJlZjogVGVtcGxhdGVSZWY8YW55PixcbiAgICBwcml2YXRlIHJlYWRvbmx5IHZpZXdDb250YWluZXJSZWY6IFZpZXdDb250YWluZXJSZWYsXG4gICAgQE9wdGlvbmFsKCkgbnJmRm9ybTogTnJmRm9ybURpcmVjdGl2ZSxcbiAgICBAT3B0aW9uYWwoKSBucmZGb3JtU2VydmljZTogTnJmRm9ybVNlcnZpY2UsXG4gICAgcHJpdmF0ZSByZWFkb25seSBmb3JtSGllcmFyY2h5OiBOcmZGb3JtSGllcmFyY2h5U2VydmljZSxcbiAgKSB7XG4gICAgdGhpcy5mb3JtT3JTZXJ2aWNlID0gbnJmRm9ybVNlcnZpY2UgfHwgbnJmRm9ybTtcbiAgfVxuXG4gIC8vIHRzbGludDpkaXNhYmxlIG5vLWlucHV0LXJlbmFtZVxuICAvKipcbiAgICogVGhlIGRvdCBub3RhdGlvbiBmdWxsIG5hbWUgb2YgdGhlIG5yZkVudGl0eVxuICAgKi9cbiAgQElucHV0KCducmZOZXN0ZWRDb250cm9sJykgbnJmTW9kZWxOYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFtBYnN0cmFjdENvbnRyb2xPcHRpb25zXXtAbGluayBodHRwczovL2FuZ3VsYXIuaW8vYXBpL2Zvcm1zL0Fic3RyYWN0Q29udHJvbE9wdGlvbnN9XG4gICAqIGNvbnRhaW5pbmcgdGhlIHZhbGlkYXRvcnMgbGlzdCBhbmQgdGhlIHVwZGF0ZS1vbiBzdHJhdGVneVxuICAgKlxuICAgKiBJdCB3aWxsIGJlIHNldCBvbiB0aGUgZm9ybUNvbnRyb2wgd2hpbGUgaW5pdGlhdGluZyBhIG5ldyBvbmUuXG4gICAqL1xuICBASW5wdXQoJ25yZk5lc3RlZENvbnRyb2xDb250cm9sT3B0aW9ucycpIGNvbnRyb2xPcHRpb25zOiBOcmZDb250cm9sT3B0aW9ucztcblxuICAvKipcbiAgICogRW1pdCByaWdodCBhZnRlciB0aGUgdmlldyB3ZXJlIHJlbmRlcmVkIGFuZCB0aGUgY29tcG9uZW50IGFuZCBpdHMgdmFyaWFibGVzIGFyYSBhdmFpbGFibGUuXG4gICAqL1xuICBAT3V0cHV0KCkgcmVhZG9ubHkgcmVhZHkkID0gbmV3IFJlcGxheVN1YmplY3QoMSk7XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVyIHRoaXMgaW5wdXQgY29tcG9uZW50IHRvIGl0cyBwYXJlbnQgZm9ybSBbRm9ybUdyb3VwXXtAbGluayBodHRwczovL2FuZ3VsYXIuaW8vYXBpL2Zvcm1zL0Zvcm1Hcm91cH1cbiAgICpcbiAgICogQW5kIHN0YXJ0cyB0byBlbWl0IHRoZSBpbnB1dCdzIHZhbHVlIHdoZW4gaXQgY2hhbmdlcy5cbiAgICovXG4gIG5nT25Jbml0KCkge1xuICAgIHRoaXMubW9kZWxQYXRoID0gdGhpcy5nZXRNb2RlbFBhdGhXaXRob3V0Rmlyc3RQYXJ0KCk7XG4gICAgdGhpcy5tb2RlbFBpZWNlcyA9IHRoaXMubW9kZWxQYXRoICYmIHRoaXMubW9kZWxQYXRoLnNwbGl0KCcuJyk7XG4gICAgdGhpcy5jb250cm9sTmFtZSA9IHRoaXMuZ2V0Q29udHJvbE5hbWUoKTtcbiAgICB0aGlzLmZvcm1Db250cm9sID0gdGhpcy5nZXRGb3JtQ29udHJvbCgpO1xuICAgIHRoaXMucmVnaXN0ZXJUb0Zvcm1Hcm91cCgpO1xuICAgIHRoaXMuc3Vic2NyaWJlVG9VcGRhdGVFbnRpdHlWYWx1ZSgpO1xuICAgIHRoaXMuc2hvd1ZpZXdDb250ZW50KCk7XG4gICAgdGhpcy5lbWl0UmVhZHlTdGF0ZSgpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgdGhpcy5pc0Rlc3Ryb3llZCA9IHRydWU7XG4gICAgdGhpcy5yZWFkeSQuY29tcGxldGUoKTtcblxuICAgIGlmICh0aGlzLnBhcmVudEZvcm1Hcm91cCkge1xuICAgICAgdGhpcy5yZW1vdmVGcm9tUGFyZW50Rm9ybUdyb3VwKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSByZW1vdmVGcm9tUGFyZW50Rm9ybUdyb3VwKCkge1xuICAgIGlmICh0aGlzLnBhcmVudEZvcm1Hcm91cCBpbnN0YW5jZW9mIEZvcm1Hcm91cCkge1xuICAgICAgdGhpcy5wYXJlbnRGb3JtR3JvdXAucmVtb3ZlQ29udHJvbCh0aGlzLm5yZk1vZGVsTmFtZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGluZGV4ID0gdGhpcy5wYXJlbnRGb3JtR3JvdXAuY29udHJvbHMuZmluZEluZGV4KChjb250cm9sOiBhbnkpID0+IHRoaXMuZm9ybUNvbnRyb2wgPT09IGNvbnRyb2wpO1xuICAgICAgdGhpcy5wYXJlbnRGb3JtR3JvdXAucmVtb3ZlQXQoaW5kZXgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIGRvdCBub3RhdGlvbiBwYXRoIG9mIHRoZSBFbnRpdHksIHdpdGhvdXQgdGhlIGZpcnN0IHBhcnQsXG4gICAqIGJlY2F1c2UgaXQgaXMgdGhlIEVudGl0eSBpdHNlbGYuXG4gICAqL1xuICBwcml2YXRlIGdldE1vZGVsUGF0aFdpdGhvdXRGaXJzdFBhcnQoKTogc3RyaW5nIHtcbiAgICBjb25zdCBtb2RlbE5hbWUgPSB0aGlzLm5yZk1vZGVsTmFtZTtcbiAgICByZXR1cm4gbW9kZWxOYW1lICYmIG1vZGVsTmFtZS5zdWJzdHIobW9kZWxOYW1lLmluZGV4T2YoJy4nKSArIDEpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGxhc3QgcGFydCBvZiB0aGUgZG90LW5vdGF0aW9uIHBhdGgsIHRoYXQgaW5kaWNhdGVzIHRoZSBjb250cm9sIG5hbWUgaXRzZWxmLlxuICAgKi9cbiAgcHJpdmF0ZSBnZXRDb250cm9sTmFtZSgpOiBzdHJpbmcge1xuICAgIGNvbnN0IG1vZGVsUGllY2VzID0gdGhpcy5tb2RlbFBpZWNlcztcbiAgICByZXR1cm4gbW9kZWxQaWVjZXMgJiYgbW9kZWxQaWVjZXNbbW9kZWxQaWVjZXMubGVuZ3RoIC0gMV07XG4gIH1cblxuICAvKipcbiAgICogSW5zdGFudGlhdGUgYSBuZXcgW0Zvcm1Db250cm9sXXtAbGluayBodHRwczovL2FuZ3VsYXIuaW8vYXBpL2Zvcm1zL0Zvcm1Db250cm9sfSBhbmQgcmV0dXJuIGl0XG4gICAqL1xuICBwcm90ZWN0ZWQgZ2V0TmV3Rm9ybUNvbnRyb2woKTogRm9ybUNvbnRyb2wge1xuICAgIGNvbnN0IGRpc2FibGVkID0gdGhpcy5jb250cm9sT3B0aW9ucyAmJiB0aGlzLmNvbnRyb2xPcHRpb25zLmRpc2FibGVkO1xuICAgIGNvbnN0IHZhbHVlID0gdGhpcy5nZXRJbml0aWFsVmFsdWUoKTtcblxuICAgIHJldHVybiBuZXcgRm9ybUNvbnRyb2woeyB2YWx1ZSwgZGlzYWJsZWQgfSwgdGhpcy5jb250cm9sT3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSB2YWx1ZSBmcm9tIHRoZSBbbnJmRW50aXR5XXtAbGluayBOcmZGb3JtRGlyZWN0aXZlI25yZkVudGl0eX1cbiAgICovXG4gIHByb3RlY3RlZCBnZXRJbml0aWFsVmFsdWUoKTogYW55IHwgbnVsbCB7XG4gICAgaWYgKHRoaXMuZm9ybU9yU2VydmljZSAmJiB0aGlzLm1vZGVsUGF0aCkge1xuICAgICAgcmV0dXJuIHRoaXMubW9kZWxTZXR0ZXIuZ2V0VmFsdWUodGhpcy5tb2RlbFBhdGgsIHRoaXMuZm9ybU9yU2VydmljZS5mb3JtRGF0YSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBwcml2YXRlIHNob3dWaWV3Q29udGVudCgpIHtcbiAgICBjb25zdCBjb250ZXh0ID0gbmV3IE5yZk5lc3RlZENvbnRyb2xDb250ZXh0KFxuICAgICAgdGhpcy5mb3JtQ29udHJvbCxcbiAgICAgIHRoaXMuZm9ybU9yU2VydmljZSAmJiB0aGlzLmZvcm1PclNlcnZpY2UuZm9ybUdyb3VwLFxuICAgICAgdGhpcyxcbiAgICApO1xuXG4gICAgdGhpcy52aWV3Q29udGFpbmVyUmVmLmNyZWF0ZUVtYmVkZGVkVmlldyh0aGlzLnRlbXBsYXRlUmVmLCBjb250ZXh0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciB0aGlzIGlucHV0IHRvIGl0cyBwYXJlbnQgW0Zvcm1Hcm91cF17QGxpbmsgaHR0cHM6Ly9hbmd1bGFyLmlvL2FwaS9mb3Jtcy9Gb3JtR3JvdXB9XG4gICAqIHRvIGVuYWJsZSB2YWxpZGF0aW9ucyBhbmQgZGF0YSBtYW5pcHVsYXRpb25cbiAgICovXG4gIHByaXZhdGUgcmVnaXN0ZXJUb0Zvcm1Hcm91cCgpIHtcbiAgICBpZiAodGhpcy5wYXJlbnRGb3JtR3JvdXApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnBhcmVudEZvcm1Hcm91cCA9IHRoaXMuZ2V0UGFyZW50Rm9ybUdyb3VwKCk7XG5cbiAgICBpZiAodGhpcy5wYXJlbnRGb3JtR3JvdXApIHtcbiAgICAgIGlmICh0aGlzLnBhcmVudEZvcm1Hcm91cCBpbnN0YW5jZW9mIEZvcm1Hcm91cCkge1xuICAgICAgICB0aGlzLnBhcmVudEZvcm1Hcm91cC5hZGRDb250cm9sKHRoaXMubW9kZWxQYXRoLCB0aGlzLmZvcm1Db250cm9sKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGluZGV4ID0gdGhpcy5jb250cm9sTmFtZTtcbiAgICAgICAgdGhpcy5wYXJlbnRGb3JtR3JvdXAuaW5zZXJ0KHBhcnNlSW50KGluZGV4LCAxMCksIHRoaXMuZm9ybUNvbnRyb2wpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZnkgaWYgdGhpcyBpbnB1dCBpcyBpbnNpZGUgYSBbTnJmRm9ybURpcmVjdGl2ZV17QGxpbmsgTnJmRm9ybURpcmVjdGl2ZX1cbiAgICogYW5kIHJldHVybiBpdHMgW0Zvcm1Hcm91cF17QGxpbmsgaHR0cHM6Ly9hbmd1bGFyLmlvL2FwaS9mb3Jtcy9Gb3JtR3JvdXB9XG4gICAqXG4gICAqIE90aGVyd2lzZSBhIG5ldyBlbXB0eSBbRm9ybUdyb3VwXXtAbGluayBodHRwczovL2FuZ3VsYXIuaW8vYXBpL2Zvcm1zL0Zvcm1Hcm91cH1cbiAgICovXG4gIHByaXZhdGUgZ2V0UGFyZW50Rm9ybUdyb3VwKCk6IEZvcm1Hcm91cCB8IEZvcm1BcnJheSB7XG4gICAgY29uc3Qgcm9vdEZvcm1Hcm91cCA9IHRoaXMuZm9ybU9yU2VydmljZSAmJiB0aGlzLmZvcm1PclNlcnZpY2UuZm9ybUdyb3VwO1xuXG4gICAgaWYgKCFyb290Rm9ybUdyb3VwIHx8ICF0aGlzLm1vZGVsUGF0aCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgY29uc3QgZm9ybUdyb3VwUGF0aCA9IEFycmF5LmZyb20odGhpcy5tb2RlbFBpZWNlcyk7XG4gICAgcmV0dXJuIHRoaXMuZm9ybUhpZXJhcmNoeS5nZXROZXN0ZWRDb250cm9sKHJvb3RGb3JtR3JvdXAsIGZvcm1Hcm91cFBhdGgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmeSBpZiB0aGUgW0Zvcm1Hcm91cF17QGxpbmsgaHR0cHM6Ly9hbmd1bGFyLmlvL2FwaS9mb3Jtcy9Gb3JtR3JvdXB9IGhhcyBhbiBjb250cm9sIHdpdGggdGhlIGN1cnJlbnQgbmFtZSBhbmQgcmV0dXJuIGl0LlxuICAgKiBPdGhlcndpc2UgcmV0dXJuIGEgbmV3IFtGb3JtQ29udHJvbF17QGxpbmsgaHR0cHM6Ly9hbmd1bGFyLmlvL2FwaS9mb3Jtcy9Gb3JtQ29udHJvbH1cbiAgICovXG4gIHByb3RlY3RlZCBnZXRGb3JtQ29udHJvbCgpOiBGb3JtQ29udHJvbCB7XG4gICAgY29uc3QgZm9ybUdyb3VwID0gdGhpcy5nZXRQYXJlbnRGb3JtR3JvdXAoKTtcbiAgICBsZXQgZm9ybUNvbnRyb2wgPSBmb3JtR3JvdXAgJiYgdGhpcy5ucmZNb2RlbE5hbWUgJiYgPEZvcm1Db250cm9sPmZvcm1Hcm91cC5nZXQodGhpcy5ucmZNb2RlbE5hbWUpO1xuXG4gICAgaWYgKCFmb3JtQ29udHJvbCkge1xuICAgICAgZm9ybUNvbnRyb2wgPSB0aGlzLmdldE5ld0Zvcm1Db250cm9sKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZvcm1Db250cm9sO1xuICB9XG5cbiAgLyoqXG4gICAqIFN1YnNjcmliZSB0byBbdmFsdWVDaGFuZ2VzXXtAbGluayBodHRwczovL2FuZ3VsYXIuaW8vYXBpL2Zvcm1zL0Fic3RyYWN0Q29udHJvbCN2YWx1ZUNoYW5nZXN9IGFuZCB1cGRhdGUgdGhlIEVudGl0eSB2YWx1ZVxuICAgKi9cbiAgcHJpdmF0ZSBzdWJzY3JpYmVUb1VwZGF0ZUVudGl0eVZhbHVlKCkge1xuICAgIHRoaXMuZm9ybUNvbnRyb2wudmFsdWVDaGFuZ2VzXG4gICAgICAucGlwZSh0YWtlV2hpbGUoKCkgPT4gIXRoaXMuaXNEZXN0cm95ZWQpKVxuICAgICAgLnN1YnNjcmliZSgobmV3VmFsdWUpID0+IHRoaXMuc2V0TW9kZWxWYWx1ZShuZXdWYWx1ZSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCB0aGUgdmFsdWUgdG8gdGhlIFtmb3JtRGF0YV17QGxpbmsgTnJmRm9ybURpcmVjdGl2ZSNmb3JtRGF0YX1cbiAgICovXG4gIHNldE1vZGVsVmFsdWUobmV3VmFsdWU6IGFueSkge1xuICAgIGlmICh0aGlzLmZvcm1PclNlcnZpY2UgJiYgdGhpcy5tb2RlbFBhdGgpIHtcbiAgICAgIHJldHVybiB0aGlzLm1vZGVsU2V0dGVyLnNldFZhbHVlKHRoaXMubW9kZWxQYXRoLCBuZXdWYWx1ZSB8fCAnJywgdGhpcy5mb3JtT3JTZXJ2aWNlLmZvcm1EYXRhKTtcbiAgICB9XG4gIH1cblxuICBlbWl0UmVhZHlTdGF0ZSgpIHtcbiAgICB0aGlzLnJlYWR5JC5uZXh0KHRoaXMpO1xuICB9XG59XG4iLCJpbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgTmdNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuaW1wb3J0IHsgTnJmQ29udHJvbE9wdGlvbnNDb21wb25lbnQgfSBmcm9tICcuL2NvbnRyb2wtb3B0aW9ucy5jb21wb25lbnQnO1xuaW1wb3J0IHsgTnJmTmVzdGVkQ29udHJvbENvbnRleHQgfSBmcm9tICcuL25lc3RlZC1jb250cm9sLWNvbnRleHQuY2xhc3MnO1xuaW1wb3J0IHsgTnJmTmVzdGVkQ29udHJvbERpcmVjdGl2ZSB9IGZyb20gJy4vbmVzdGVkLWNvbnRyb2wuZGlyZWN0aXZlJztcbmltcG9ydCB7IE5yZkZvcm1IaWVyYXJjaHlTZXJ2aWNlIH0gZnJvbSAnLi9zZXJ2aWNlcy9mb3JtLWhpZXJhcmNoeS5zZXJ2aWNlJztcbmltcG9ydCB7IE5yZk1vZGVsU2V0dGVyU2VydmljZSB9IGZyb20gJy4vc2VydmljZXMvbW9kZWwtc2V0dGVyLnNlcnZpY2UnO1xuXG5cbmV4cG9ydCB7XG4gIE5yZk5lc3RlZENvbnRyb2xEaXJlY3RpdmUsXG4gIE5yZk5lc3RlZENvbnRyb2xDb250ZXh0LFxuICBOcmZNb2RlbFNldHRlclNlcnZpY2UsXG4gIE5yZkNvbnRyb2xPcHRpb25zQ29tcG9uZW50LFxuICBOcmZGb3JtSGllcmFyY2h5U2VydmljZSxcbn07XG5cbi8qIHRzbGludDpkaXNhYmxlIHRlci1wYWRkZWQtYmxvY2tzICovXG5cbi8qKlxuICogSG9sZHMgdGhlIG5yZk1vZGVsIGRpcmVjdGl2ZSBpbXBsZW1lbnRhdGlvblxuICovXG5ATmdNb2R1bGUoe1xuICBpbXBvcnRzOltcbiAgICBDb21tb25Nb2R1bGUsXG4gIF0sXG4gIHByb3ZpZGVyczogW1xuICAgIE5yZk1vZGVsU2V0dGVyU2VydmljZSxcbiAgICBOcmZGb3JtSGllcmFyY2h5U2VydmljZSxcbiAgXSxcbiAgZGVjbGFyYXRpb25zOiBbXG4gICAgTnJmTmVzdGVkQ29udHJvbERpcmVjdGl2ZSxcbiAgXSxcbiAgZXhwb3J0czogW1xuICAgIE5yZk5lc3RlZENvbnRyb2xEaXJlY3RpdmUsXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIE5yZk1vZGVsTW9kdWxlIHt9XG4iLCJpbXBvcnQgeyBOZ01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbXBvcnQgeyBOcmZGb3JtTW9kdWxlIH0gZnJvbSAnLi9mb3JtL2Zvcm0ubW9kdWxlJztcbmltcG9ydCB7IE5yZk1vZGVsTW9kdWxlIH0gZnJvbSAnLi9uZXN0ZWQtY29udHJvbC9uZXN0ZWQtY29udHJvbC5tb2R1bGUnO1xuXG5leHBvcnQgKiBmcm9tICcuL3V0aWxzL2Nsb25lLWRlZXAnO1xuXG5ATmdNb2R1bGUoe1xuICBleHBvcnRzOiBbXG4gICAgTnJmRm9ybU1vZHVsZSxcbiAgICBOcmZNb2RlbE1vZHVsZSxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgTnJGb3Jtc01vZHVsZSB7IH1cbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7TUFJYSxjQUFjO0lBSXpCLFlBQW1CLE9BQXlCO1FBQXpCLFlBQU8sR0FBUCxPQUFPLENBQWtCO1FBQzFDLElBQUksQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDO1FBQ3pCLElBQUksQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQztLQUNwQztDQUNGOztNQ1JZLGFBQWE7SUFPeEIsWUFBWSxPQUF5QixFQUFFLE1BQWE7UUFDbEQsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFP