@webdev-tools/ng-nested-reactive-forms
Version:
Implement Nested FormControl for Angular Reactive Forms.
577 lines (557 loc) • 89.2 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('@angular/forms'), require('rxjs/internal/ReplaySubject'), require('rxjs/operators'), require('@angular/common')) :
typeof define === 'function' && define.amd ? define('@webdev-tools/ng-nested-reactive-forms', ['exports', '@angular/core', '@angular/forms', 'rxjs/internal/ReplaySubject', 'rxjs/operators', '@angular/common'], factory) :
(factory((global['webdev-tools'] = global['webdev-tools'] || {}, global['webdev-tools']['ng-nested-reactive-forms'] = {}),global.ng.core,global.ng.forms,global.rxjs['internal/ReplaySubject'],global.rxjs.operators,global.ng.common));
}(this, (function (exports,core,forms,ReplaySubject,operators,common) { 'use strict';
var NrfFormContext = (function () {
function NrfFormContext(nrfForm) {
this.nrfForm = nrfForm;
this.$implicit = nrfForm;
this.formGroup = nrfForm.formGroup;
}
return NrfFormContext;
}());
var NrfSubmitData = (function () {
function NrfSubmitData(nrfForm, $event) {
this.nrfForm = nrfForm;
this.event = $event;
this.formData = nrfForm.formData;
this.entity = nrfForm.nrfEntity;
this.formGroup = nrfForm.formGroup;
}
return NrfSubmitData;
}());
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(function (props, key) {
props[key] = cloneDeep(target[key]);
return props;
}, {});
}
var NrfFormService = (function () {
function NrfFormService() {
this.formGroup = new forms.FormGroup({});
this.submit$ = new core.EventEmitter();
}
Object.defineProperty(NrfFormService.prototype, "entity", {
get: function () {
return this.privateEntity;
},
set: function (entity) {
this.privateEntity = entity;
this.formData = cloneDeep(entity);
},
enumerable: true,
configurable: true
});
NrfFormService.decorators = [
{ type: core.Injectable }
];
return NrfFormService;
}());
function newNrfFormService() {
return new NrfFormService();
}
var NRF_FORM_SERVICE_PROVIDER = {
provide: NrfFormService,
useFactory: newNrfFormService,
};
var NrfFormDirective = (function () {
function NrfFormDirective(templateRef, viewContainerRef, formService, renderer) {
this.templateRef = templateRef;
this.viewContainerRef = viewContainerRef;
this.formService = formService;
this.renderer = renderer;
if (!formService) {
this.formService = new NrfFormService();
}
}
Object.defineProperty(NrfFormDirective.prototype, "nrfEntity", {
get: function () {
return this.formService.entity;
},
set: function (entity) {
this.formService.entity = entity;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NrfFormDirective.prototype, "formData", {
get: function () {
return this.formService.formData;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NrfFormDirective.prototype, "formGroup", {
get: function () {
return this.formService.formGroup;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NrfFormDirective.prototype, "nrfSubmit", {
get: function () {
return this.formService.submit$;
},
enumerable: true,
configurable: true
});
NrfFormDirective.prototype.ngOnInit = function () {
if (!this.nrfEntity) {
this.nrfEntity = {};
}
this.renderView();
};
NrfFormDirective.prototype.ngOnDestroy = function () {
this.nrfSubmit.complete();
};
NrfFormDirective.prototype.renderView = function () {
var _this = this;
if (this.templateRef && this.viewContainerRef) {
var embeddedViewRef = this.viewContainerRef.createEmbeddedView(this.templateRef, new NrfFormContext(this));
var formNative = embeddedViewRef.rootNodes[0];
this.renderer.listen(formNative, 'submit', function (event) { return _this.formSubmitWrapper(event); });
}
};
NrfFormDirective.prototype.formSubmitWrapper = function ($event) {
$event.preventDefault();
if (!this.formGroup.valid) {
return;
}
this.nrfSubmit.emit(new NrfSubmitData(this, $event));
};
NrfFormDirective.decorators = [
{ type: core.Directive, args: [{
selector: '[nrfForm]',
exportAs: 'nrfForm',
},] }
];
NrfFormDirective.ctorParameters = function () {
return [
{ type: core.TemplateRef, decorators: [{ type: core.Optional }] },
{ type: core.ViewContainerRef, decorators: [{ type: core.Optional }] },
{ type: NrfFormService, decorators: [{ type: core.Optional }] },
{ type: core.Renderer2 }
];
};
NrfFormDirective.propDecorators = {
nrfEntity: [{ type: core.Input }],
nrfSubmit: [{ type: core.Output }],
formSubmitWrapper: [{ type: core.HostListener, args: ['submit', ['$event'],] }]
};
return NrfFormDirective;
}());
var NrfFormModule = (function () {
function NrfFormModule() {
}
NrfFormModule.decorators = [
{ type: core.NgModule, args: [{
imports: [forms.FormsModule, forms.ReactiveFormsModule],
exports: [forms.FormsModule, forms.ReactiveFormsModule, NrfFormDirective],
declarations: [NrfFormDirective],
},] }
];
return NrfFormModule;
}());
var NrfControlOptionsComponent = (function () {
function NrfControlOptionsComponent() {
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;
}
NrfControlOptionsComponent.prototype.ngOnInit = function () {
this.controlOptions = this.generateControlOptions();
};
NrfControlOptionsComponent.prototype.generateControlOptions = function () {
var _this = this;
return {
validators: Object.keys(forms.Validators)
.filter(function (key) { return _this[key]; })
.map(function (key) { return forms.Validators[key]; }),
updateOn: this.updateOn,
disabled: this.disabled,
};
};
NrfControlOptionsComponent.propDecorators = {
disabled: [{ type: core.Input, args: ['disabled',] }],
min: [{ type: core.Input, args: ['min',] }],
max: [{ type: core.Input, args: ['max',] }],
required: [{ type: core.Input, args: ['required',] }],
email: [{ type: core.Input, args: ['email',] }],
minLength: [{ type: core.Input, args: ['minLength',] }],
maxLength: [{ type: core.Input, args: ['maxLength',] }],
pattern: [{ type: core.Input, args: ['pattern',] }],
updateOn: [{ type: core.Input, args: ['updateOn',] }]
};
return NrfControlOptionsComponent;
}());
var NrfNestedControlContext = (function () {
function NrfNestedControlContext(formControl, formGroup, nrfNestedControl) {
this.formControl = formControl;
this.formGroup = formGroup;
this.nrfNestedControl = nrfNestedControl;
this.$implicit = formControl;
}
return NrfNestedControlContext;
}());
var NrfFormHierarchyService = (function () {
function NrfFormHierarchyService() {
}
NrfFormHierarchyService.prototype.getNestedControl = function (rootFormGroup, fullPath) {
var parentControl = ((rootFormGroup.get(fullPath)));
if (!parentControl) {
var pathPieces = Array.isArray(fullPath) ? fullPath : fullPath.split('.');
parentControl = pathPieces.reduce(this.createFormGroupHierarchy, rootFormGroup);
}
if (parentControl instanceof forms.FormControl) {
parentControl = parentControl.parent;
}
return parentControl;
};
NrfFormHierarchyService.prototype.createFormGroupHierarchy = function (parentControl, path, index, pathPieces) {
if (index === pathPieces.length - 1) {
return parentControl;
}
var control = ((parentControl.get(path)));
if (!control) {
var nextPath = pathPieces[index + 1] || path;
var isArray = nextPath && !isNaN(((nextPath)));
control = isArray ? new forms.FormArray([]) : new forms.FormGroup({});
}
if (parentControl instanceof forms.FormGroup) {
parentControl.addControl(path, control);
}
else if (parentControl instanceof forms.FormArray) {
parentControl.insert(parseInt(path, 10) || 0, control);
}
return control;
};
NrfFormHierarchyService.decorators = [
{ type: core.Injectable }
];
return NrfFormHierarchyService;
}());
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
var __assign = function () {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s)
if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __read(o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m)
return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done)
ar.push(r.value);
}
catch (error) {
e = { error: error };
}
finally {
try {
if (r && !r.done && (m = i["return"]))
m.call(i);
}
finally {
if (e)
throw e.error;
}
}
return ar;
}
function __spread() {
for (var ar = [], i = 0; i < arguments.length; i++)
ar = ar.concat(__read(arguments[i]));
return ar;
}
var NrfModelSetterService = (function () {
function NrfModelSetterService() {
var _this = this;
this.getTargetPropToSet = function (obj, key, i, pathPieces) {
var nextKey = pathPieces[i + 1];
var isLast = nextKey == null;
nextKey = nextKey || pathPieces['finalKey'];
var isArrayKey = _this.isArrayKey(nextKey);
var prop = obj[key];
if (!prop) {
prop = isArrayKey ? [] : {};
obj[key] = prop;
}
else if (isLast) {
prop = isArrayKey ? __spread(prop) : __assign({}, prop);
obj[key] = prop;
}
return prop;
};
}
NrfModelSetterService.prototype.getValue = function (path, model, separator) {
if (separator === void 0) {
separator = '.';
}
if (path == null || !model) {
return null;
}
try {
var pathPieces = this.generatePathPieces(path, separator);
return pathPieces.reduce(this.piecesReducer, model) || null;
}
catch (err) {
return null;
}
};
NrfModelSetterService.prototype.piecesReducer = function (obj, key) {
return key === '' ? obj.slice(-1)[0] : obj[key];
};
NrfModelSetterService.prototype.setValue = function (path, value, model, separator) {
if (separator === void 0) {
separator = '.';
}
if (!(path && model)) {
return null;
}
try {
var pathPieces = this.generatePathPieces(path, separator);
var finalKey = pathPieces.pop();
(((pathPieces)))['finalKey'] = finalKey;
var targetProp = pathPieces.reduce(this.getTargetPropToSet, model) || null;
if (finalKey === '') {
targetProp.push(value);
}
else {
targetProp[finalKey] = value;
}
}
catch (err) {
console.error('NestedProps setValue error: ', err);
}
};
NrfModelSetterService.prototype.isArrayKey = function (key) {
return key === '' || !isNaN(parseInt(key, 10));
};
NrfModelSetterService.prototype.generatePathPieces = function (path, separator) {
return path
.replace('[', separator)
.replace(']', '')
.split(separator);
};
NrfModelSetterService.decorators = [
{ type: core.Injectable }
];
return NrfModelSetterService;
}());
var NrfNestedControlDirective = (function () {
function NrfNestedControlDirective(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.ReplaySubject(1);
this.formOrService = nrfFormService || nrfForm;
}
NrfNestedControlDirective.prototype.ngOnInit = function () {
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();
};
NrfNestedControlDirective.prototype.ngOnDestroy = function () {
this.isDestroyed = true;
this.ready$.complete();
if (this.parentFormGroup) {
this.removeFromParentFormGroup();
}
};
NrfNestedControlDirective.prototype.removeFromParentFormGroup = function () {
var _this = this;
if (this.parentFormGroup instanceof forms.FormGroup) {
this.parentFormGroup.removeControl(this.nrfModelName);
}
else {
var index = this.parentFormGroup.controls.findIndex(function (control) { return _this.formControl === control; });
this.parentFormGroup.removeAt(index);
}
};
NrfNestedControlDirective.prototype.getModelPathWithoutFirstPart = function () {
var modelName = this.nrfModelName;
return modelName && modelName.substr(modelName.indexOf('.') + 1);
};
NrfNestedControlDirective.prototype.getControlName = function () {
var modelPieces = this.modelPieces;
return modelPieces && modelPieces[modelPieces.length - 1];
};
NrfNestedControlDirective.prototype.getNewFormControl = function () {
var disabled = this.controlOptions && this.controlOptions.disabled;
var value = this.getInitialValue();
return new forms.FormControl({ value: value, disabled: disabled }, this.controlOptions);
};
NrfNestedControlDirective.prototype.getInitialValue = function () {
if (this.formOrService && this.modelPath) {
return this.modelSetter.getValue(this.modelPath, this.formOrService.formData);
}
return null;
};
NrfNestedControlDirective.prototype.showViewContent = function () {
var context = new NrfNestedControlContext(this.formControl, this.formOrService && this.formOrService.formGroup, this);
this.viewContainerRef.createEmbeddedView(this.templateRef, context);
};
NrfNestedControlDirective.prototype.registerToFormGroup = function () {
if (this.parentFormGroup) {
return;
}
this.parentFormGroup = this.getParentFormGroup();
if (this.parentFormGroup) {
if (this.parentFormGroup instanceof forms.FormGroup) {
this.parentFormGroup.addControl(this.modelPath, this.formControl);
}
else {
var index = this.controlName;
this.parentFormGroup.insert(parseInt(index, 10), this.formControl);
}
}
};
NrfNestedControlDirective.prototype.getParentFormGroup = function () {
var rootFormGroup = this.formOrService && this.formOrService.formGroup;
if (!rootFormGroup || !this.modelPath) {
return null;
}
var formGroupPath = Array.from(this.modelPieces);
return this.formHierarchy.getNestedControl(rootFormGroup, formGroupPath);
};
NrfNestedControlDirective.prototype.getFormControl = function () {
var formGroup = this.getParentFormGroup();
var formControl = formGroup && this.nrfModelName && ((formGroup.get(this.nrfModelName)));
if (!formControl) {
formControl = this.getNewFormControl();
}
return formControl;
};
NrfNestedControlDirective.prototype.subscribeToUpdateEntityValue = function () {
var _this = this;
this.formControl.valueChanges
.pipe(operators.takeWhile(function () { return !_this.isDestroyed; }))
.subscribe(function (newValue) { return _this.setModelValue(newValue); });
};
NrfNestedControlDirective.prototype.setModelValue = function (newValue) {
if (this.formOrService && this.modelPath) {
return this.modelSetter.setValue(this.modelPath, newValue || '', this.formOrService.formData);
}
};
NrfNestedControlDirective.prototype.emitReadyState = function () {
this.ready$.next(this);
};
NrfNestedControlDirective.decorators = [
{ type: core.Directive, args: [{
selector: '[nrfNestedControl]',
exportAs: 'nrfNestedControl',
},] }
];
NrfNestedControlDirective.ctorParameters = function () {
return [
{ type: NrfModelSetterService },
{ type: core.TemplateRef },
{ type: core.ViewContainerRef },
{ type: NrfFormDirective, decorators: [{ type: core.Optional }] },
{ type: NrfFormService, decorators: [{ type: core.Optional }] },
{ type: NrfFormHierarchyService }
];
};
NrfNestedControlDirective.propDecorators = {
nrfModelName: [{ type: core.Input, args: ['nrfNestedControl',] }],
controlOptions: [{ type: core.Input, args: ['nrfNestedControlControlOptions',] }],
ready$: [{ type: core.Output }]
};
return NrfNestedControlDirective;
}());
var NrfModelModule = (function () {
function NrfModelModule() {
}
NrfModelModule.decorators = [
{ type: core.NgModule, args: [{
imports: [
common.CommonModule,
],
providers: [
NrfModelSetterService,
NrfFormHierarchyService,
],
declarations: [
NrfNestedControlDirective,
],
exports: [
NrfNestedControlDirective,
],
},] }
];
return NrfModelModule;
}());
var NrFormsModule = (function () {
function NrFormsModule() {
}
NrFormsModule.decorators = [
{ type: core.NgModule, args: [{
exports: [
NrfFormModule,
NrfModelModule,
],
},] }
];
return NrFormsModule;
}());
exports.NrFormsModule = NrFormsModule;
exports.cloneDeep = cloneDeep;
exports.NrfFormDirective = NrfFormDirective;
exports.NrfFormContext = NrfFormContext;
exports.NrfSubmitData = NrfSubmitData;
exports.NrfFormService = NrfFormService;
exports.NRF_FORM_SERVICE_PROVIDER = NRF_FORM_SERVICE_PROVIDER;
exports.NrfFormModule = NrfFormModule;
exports.NrfNestedControlDirective = NrfNestedControlDirective;
exports.NrfNestedControlContext = NrfNestedControlContext;
exports.NrfModelSetterService = NrfModelSetterService;
exports.NrfControlOptionsComponent = NrfControlOptionsComponent;
exports.NrfFormHierarchyService = NrfFormHierarchyService;
exports.NrfModelModule = NrfModelModule;
exports.ɵa = newNrfFormService;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViZGV2LXRvb2xzLW5nLW5lc3RlZC1yZWFjdGl2ZS1mb3Jtcy51bWQuanMubWFwIiwic291cmNlcyI6WyJuZzovL0B3ZWJkZXYtdG9vbHMvbmctbmVzdGVkLXJlYWN0aXZlLWZvcm1zL2xpYi9mb3JtL2Zvcm0tY29udGV4dC5jbGFzcy50cyIsIm5nOi8vQHdlYmRldi10b29scy9uZy1uZXN0ZWQtcmVhY3RpdmUtZm9ybXMvbGliL2Zvcm0vZm9ybS1zdWJtaXQtZGF0YS5jbGFzcy50cyIsIm5nOi8vQHdlYmRldi10b29scy9uZy1uZXN0ZWQtcmVhY3RpdmUtZm9ybXMvbGliL3V0aWxzL2Nsb25lLWRlZXAudHMiLCJuZzovL0B3ZWJkZXYtdG9vbHMvbmctbmVzdGVkLXJlYWN0aXZlLWZvcm1zL2xpYi9mb3JtL2Zvcm0uc2VydmljZS50cyIsIm5nOi8vQHdlYmRldi10b29scy9uZy1uZXN0ZWQtcmVhY3RpdmUtZm9ybXMvbGliL2Zvcm0vZm9ybS5kaXJlY3RpdmUudHMiLCJuZzovL0B3ZWJkZXYtdG9vbHMvbmctbmVzdGVkLXJlYWN0aXZlLWZvcm1zL2xpYi9mb3JtL2Zvcm0ubW9kdWxlLnRzIiwibmc6Ly9Ad2ViZGV2LXRvb2xzL25nLW5lc3RlZC1yZWFjdGl2ZS1mb3Jtcy9saWIvbmVzdGVkLWNvbnRyb2wvY29udHJvbC1vcHRpb25zLmNvbXBvbmVudC50cyIsIm5nOi8vQHdlYmRldi10b29scy9uZy1uZXN0ZWQtcmVhY3RpdmUtZm9ybXMvbGliL25lc3RlZC1jb250cm9sL25lc3RlZC1jb250cm9sLWNvbnRleHQuY2xhc3MudHMiLCJuZzovL0B3ZWJkZXYtdG9vbHMvbmctbmVzdGVkLXJlYWN0aXZlLWZvcm1zL2xpYi9uZXN0ZWQtY29udHJvbC9zZXJ2aWNlcy9mb3JtLWhpZXJhcmNoeS5zZXJ2aWNlLnRzIiwibm9kZV9tb2R1bGVzL3RzbGliL3RzbGliLmVzNi5qcyIsIm5nOi8vQHdlYmRldi10b29scy9uZy1uZXN0ZWQtcmVhY3RpdmUtZm9ybXMvbGliL25lc3RlZC1jb250cm9sL3NlcnZpY2VzL21vZGVsLXNldHRlci5zZXJ2aWNlLnRzIiwibmc6Ly9Ad2ViZGV2LXRvb2xzL25nLW5lc3RlZC1yZWFjdGl2ZS1mb3Jtcy9saWIvbmVzdGVkLWNvbnRyb2wvbmVzdGVkLWNvbnRyb2wuZGlyZWN0aXZlLnRzIiwibmc6Ly9Ad2ViZGV2LXRvb2xzL25nLW5lc3RlZC1yZWFjdGl2ZS1mb3Jtcy9saWIvbmVzdGVkLWNvbnRyb2wvbmVzdGVkLWNvbnRyb2wubW9kdWxlLnRzIiwibmc6Ly9Ad2ViZGV2LXRvb2xzL25nLW5lc3RlZC1yZWFjdGl2ZS1mb3Jtcy9saWIvZm9ybXMubW9kdWxlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEZvcm1Hcm91cCB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcblxuaW1wb3J0IHsgTnJmRm9ybURpcmVjdGl2ZSB9IGZyb20gJy4vZm9ybS5kaXJlY3RpdmUnO1xuXG5leHBvcnQgY2xhc3MgTnJmRm9ybUNvbnRleHQge1xuICAkaW1wbGljaXQ6IE5yZkZvcm1EaXJlY3RpdmU7XG4gIGZvcm1Hcm91cDogRm9ybUdyb3VwO1xuXG4gIGNvbnN0cnVjdG9yKHB1YmxpYyBucmZGb3JtOiBOcmZGb3JtRGlyZWN0aXZlKSB7XG4gICAgdGhpcy4kaW1wbGljaXQgPSBucmZGb3JtO1xuICAgIHRoaXMuZm9ybUdyb3VwID0gbnJmRm9ybS5mb3JtR3JvdXA7XG4gIH1cbn1cbiIsImltcG9ydCB7IEZvcm1Hcm91cCB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcblxuaW1wb3J0IHsgTnJmRm9ybURpcmVjdGl2ZSB9IGZyb20gJy4vZm9ybS5kaXJlY3RpdmUnO1xuXG5leHBvcnQgY2xhc3MgTnJmU3VibWl0RGF0YSB7XG4gIG5yZkZvcm06IE5yZkZvcm1EaXJlY3RpdmU7XG4gIGZvcm1EYXRhOiBhbnk7XG4gIGVudGl0eTogYW55O1xuICBmb3JtR3JvdXA6IEZvcm1Hcm91cDtcbiAgZXZlbnQ6IEV2ZW50O1xuXG4gIGNvbnN0cnVjdG9yKG5yZkZvcm06IE5yZkZvcm1EaXJlY3RpdmUsICRldmVudDogRXZlbnQpIHtcbiAgICB0aGlzLm5yZkZvcm0gPSBucmZGb3JtO1xuICAgIHRoaXMuZXZlbnQgPSAkZXZlbnQ7XG4gICAgdGhpcy5mb3JtRGF0YSA9IG5yZkZvcm0uZm9ybURhdGE7XG4gICAgdGhpcy5lbnRpdHkgPSBucmZGb3JtLm5yZkVudGl0eTtcbiAgICB0aGlzLmZvcm1Hcm91cCA9IG5yZkZvcm0uZm9ybUdyb3VwO1xuICB9XG59XG4iLCJleHBvcnQgZnVuY3Rpb24gY2xvbmVEZWVwKHRhcmdldDogYW55IHwgYW55W10pOiBhbnkge1xuICBpZiAoIXRhcmdldCB8fCB0eXBlb2YgdGFyZ2V0ICE9PSAnb2JqZWN0Jykge1xuICAgIHJldHVybiB0YXJnZXQ7XG4gIH1cblxuICBpZiAodGFyZ2V0IGluc3RhbmNlb2YgRGF0ZSkge1xuICAgIHJldHVybiBuZXcgRGF0ZSh0YXJnZXQpO1xuICB9XG5cbiAgaWYgKEFycmF5LmlzQXJyYXkodGFyZ2V0KSkge1xuICAgIHJldHVybiB0YXJnZXQubWFwKGNsb25lRGVlcCk7XG4gIH1cblxuICByZXR1cm4gT2JqZWN0LmtleXModGFyZ2V0KS5yZWR1Y2UoXG4gICAgKHByb3BzLCBrZXkpID0+IHtcbiAgICAgIHByb3BzW2tleV0gPSBjbG9uZURlZXAodGFyZ2V0W2tleV0pO1xuICAgICAgcmV0dXJuIHByb3BzO1xuICAgIH0sXG4gICAge30sXG4gICk7XG59XG4iLCJpbXBvcnQgeyBFdmVudEVtaXR0ZXIsIEluamVjdGFibGUsIFByb3ZpZGVyIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBGb3JtR3JvdXAgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5cbmltcG9ydCB7IGNsb25lRGVlcCB9IGZyb20gJy4uL3V0aWxzL2Nsb25lLWRlZXAnO1xuaW1wb3J0IHsgTnJmU3VibWl0RGF0YSB9IGZyb20gJy4vZm9ybS1zdWJtaXQtZGF0YS5jbGFzcyc7XG5cbi8qIHRzbGludDpkaXNhYmxlIHRlci1wYWRkZWQtYmxvY2tzICovXG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBOcmZGb3JtU2VydmljZSB7XG4gIC8qKlxuICAgKiBGb3JtIGdyb3VwIHdpbGwgaG9sZCBhbGwgaW5wdXRzIHdpdGhpbiB0aGlzIGZvcm0uXG4gICAqXG4gICAqIEV2ZXJ5IGlucHV0IHNob3VsZCByZWdpc3RlciBpdHNlbGYgdG8gdGhpcyBmb3JtIGdyb3VwLlxuICAgKlxuICAgKiBUaGUgZGF0YSBpbiB0aGlzIGZvcm0gZ3JvdXAgd2lsbCBub3QgYmUgc2VudCB0byBiYWNrZW5kLCBqdXN0IGZvcm0gdmFsaWRhdGlvbnMgYW5kIGlucHV0IG1hbmFnZW1lbnQuXG4gICAqL1xuICByZWFkb25seSBmb3JtR3JvdXA6IEZvcm1Hcm91cCA9IG5ldyBGb3JtR3JvdXAoe30pO1xuXG4gIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTp2YXJpYWJsZS1uYW1lXG4gIHByaXZhdGUgcHJpdmF0ZUVudGl0eTogYW55O1xuXG4gIHNldCBlbnRpdHkoZW50aXR5OiBhbnkpIHtcbiAgICB0aGlzLnByaXZhdGVFbnRpdHkgPSBlbnRpdHk7XG4gICAgdGhpcy5mb3JtRGF0YSA9IGNsb25lRGVlcChlbnRpdHkpOyAvLyBUT0RPIG1lcmdlIHdpdGggZXhpc3RlbnQgZm9ybURhdGFcbiAgfVxuICBnZXQgZW50aXR5KCkge1xuICAgIHJldHVybiB0aGlzLnByaXZhdGVFbnRpdHk7XG4gIH1cblxuICAvKipcbiAgICogUmVwcmVzZW50cyB0aGUgZGF0YSBpbnB1dHRlZCBieSB0aGUgdXNlciBvbiB0aGUgZmllbGRzXG4gICAqL1xuICBmb3JtRGF0YTogYW55O1xuXG4gIC8qKlxuICAgKiBJbnRlcm5hbCBlbWl0dGVyIHRvIGhhbmRsZSBmb3JtIHN1Ym1pdFxuICAgKi9cbiAgcmVhZG9ubHkgc3VibWl0JCA9IG5ldyBFdmVudEVtaXR0ZXI8TnJmU3VibWl0RGF0YT4oKTtcbn1cblxuLyoqXG4gKiBAaWdub3JlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBuZXdOcmZGb3JtU2VydmljZSgpIHtcbiAgcmV0dXJuIG5ldyBOcmZGb3JtU2VydmljZSgpO1xufVxuXG4vKipcbiAqIFVzZSB0aGlzIHRvIHByb3ZpZGUgZm9ybS1zZXJ2aWNlIHRvIENvbXBvbmVudHMgdGhhdCB3cmFwcyBucmZGb3JtIGFuZCBwdXQgaW5wdXRzIGluc2lkZSA8bmctY29udGVudD5cbiAqL1xuZXhwb3J0IGNvbnN0IE5SRl9GT1JNX1NFUlZJQ0VfUFJPVklERVI6IFByb3ZpZGVyID0ge1xuICBwcm92aWRlOiBOcmZGb3JtU2VydmljZSxcbiAgdXNlRmFjdG9yeTogbmV3TnJmRm9ybVNlcnZpY2UsXG59O1xuIiwiaW1wb3J0IHtcbiAgRGlyZWN0aXZlLFxuICBFdmVudEVtaXR0ZXIsXG4gIEhvc3RMaXN0ZW5lcixcbiAgSW5wdXQsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBPcHRpb25hbCxcbiAgT3V0cHV0LFxuICBSZW5kZXJlcjIsXG4gIFRlbXBsYXRlUmVmLFxuICBWaWV3Q29udGFpbmVyUmVmLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZvcm1Hcm91cCB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcblxuaW1wb3J0IHsgTnJmRm9ybUNvbnRleHQgfSBmcm9tICcuL2Zvcm0tY29udGV4dC5jbGFzcyc7XG5pbXBvcnQgeyBOcmZTdWJtaXREYXRhIH0gZnJvbSAnLi9mb3JtLXN1Ym1pdC1kYXRhLmNsYXNzJztcbmltcG9ydCB7IE5yZkZvcm1TZXJ2aWNlIH0gZnJvbSAnLi9mb3JtLnNlcnZpY2UnO1xuXG4vKiB0c2xpbnQ6ZGlzYWJsZTogdGVyLXBhZGRlZC1ibG9ja3MgKi9cbi8qKlxuICogQSBjb21wb25lbnQgdG8gYWJzdHJhY3QgdGhlIGZvcm0gaW1wbGVtZW50YXRpb25cbiAqXG4gKiBJdCBob2xkcyB0aGUgdmFsaWRhdGlvbiBhbmQgdGhlIHN1Ym1pdCBsb2dpY1xuICpcbiAqIEBleGFtcGxlXG4gKiA8Zm9ybSBucmZGb3JtIChucmZTdWJtaXQpPVwiYUNhbGxiYWNrKCRldmVudClcIj5cbiAqICAvLyBJbnB1dHNcbiAqIDwvZm9ybT5cbiAqL1xuQERpcmVjdGl2ZSh7XG4gIHNlbGVjdG9yOiAnW25yZkZvcm1dJyxcbiAgZXhwb3J0QXM6ICducmZGb3JtJyxcbn0pXG5leHBvcnQgY2xhc3MgTnJmRm9ybURpcmVjdGl2ZSBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgLyoqXG4gICAqIEBpZ25vcmVcbiAgICovXG4gIGNvbnN0cnVjdG9yKFxuICAgIEBPcHRpb25hbCgpIHByaXZhdGUgcmVhZG9ubHkgdGVtcGxhdGVSZWY6IFRlbXBsYXRlUmVmPGFueT4sXG4gICAgQE9wdGlvbmFsKCkgcHJpdmF0ZSByZWFkb25seSB2aWV3Q29udGFpbmVyUmVmOiBWaWV3Q29udGFpbmVyUmVmLFxuICAgIEBPcHRpb25hbCgpIHByaXZhdGUgcmVhZG9ubHkgZm9ybVNlcnZpY2U6IE5yZkZvcm1TZXJ2aWNlLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgcmVuZGVyZXI6IFJlbmRlcmVyMixcbiAgKSB7XG4gICAgaWYgKCFmb3JtU2VydmljZSkge1xuICAgICAgdGhpcy5mb3JtU2VydmljZSA9IG5ldyBOcmZGb3JtU2VydmljZSgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXByZXNlbnRzIGFuIEVudGl0eSBNb2RlbCB0aGF0IGNvbWVzIGZyb20gRGF0YWJhc2VcbiAgICovXG4gIEBJbnB1dCgpXG4gIHNldCBucmZFbnRpdHkoZW50aXR5OiBhbnkpIHtcbiAgICB0aGlzLmZvcm1TZXJ2aWNlLmVudGl0eSA9IGVudGl0eTtcbiAgfVxuICBnZXQgbnJmRW50aXR5KCk6IGFueSB7XG4gICAgcmV0dXJuIHRoaXMuZm9ybVNlcnZpY2UuZW50aXR5O1xuICB9XG5cbiAgZ2V0IGZvcm1EYXRhKCk6IGFueSB7XG4gICAgcmV0dXJuIHRoaXMuZm9ybVNlcnZpY2UuZm9ybURhdGE7XG4gIH1cblxuICBnZXQgZm9ybUdyb3VwKCk6IEZvcm1Hcm91cCB7XG4gICAgcmV0dXJuIHRoaXMuZm9ybVNlcnZpY2UuZm9ybUdyb3VwO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgZnVuY3Rpb24gdGhhdCB3aWxsIGJlIGNhbGxlZCB3aGVuIHRoZSBmb3JtIGlzIHZhbGlkIGFuZCBhIHN1Ym1pdCBldmVudCBpcyB0cmlnZ2VyZWRcbiAgICogYnkgYSBidXR0b24gY2xpY2sgb3IgcHJvZ3JhbW1hdGljYWxseS5cbiAgICovXG4gIEBPdXRwdXQoKVxuICBnZXQgbnJmU3VibWl0KCk6IEV2ZW50RW1pdHRlcjxOcmZTdWJtaXREYXRhPiB7XG4gICAgcmV0dXJuIHRoaXMuZm9ybVNlcnZpY2Uuc3VibWl0JDtcbiAgfVxuXG5cbiAgLyoqXG4gICAqIEluaXQgYW4gZW1wdHkgbnJmRW50aXR5LCBpbiBjYXNlIG5vbmUgd2hlcmUgcHJvdmlkZWQuXG4gICAqL1xuICBuZ09uSW5pdCgpIHtcbiAgICBpZiAoIXRoaXMubnJmRW50aXR5KSB7XG4gICAgICB0aGlzLm5yZkVudGl0eSA9IHt9O1xuICAgIH1cblxuICAgIHRoaXMucmVuZGVyVmlldygpO1xuICB9XG5cblxuICBuZ09uRGVzdHJveSgpIHtcbiAgICB0aGlzLm5yZlN1Ym1pdC5jb21wbGV0ZSgpO1xuICB9XG5cblxuICBwcml2YXRlIHJlbmRlclZpZXcoKSB7XG4gICAgaWYgKHRoaXMudGVtcGxhdGVSZWYgJiYgdGhpcy52aWV3Q29udGFpbmVyUmVmKSB7XG4gICAgICBjb25zdCBlbWJlZGRlZFZpZXdSZWYgPSB0aGlzLnZpZXdDb250YWluZXJSZWYuY3JlYXRlRW1iZWRkZWRWaWV3KHRoaXMudGVtcGxhdGVSZWYsIG5ldyBOcmZGb3JtQ29udGV4dCh0aGlzKSk7XG4gICAgICBjb25zdCBmb3JtTmF0aXZlID0gZW1iZWRkZWRWaWV3UmVmLnJvb3ROb2Rlc1swXTtcbiAgICAgIHRoaXMucmVuZGVyZXIubGlzdGVuKGZvcm1OYXRpdmUsICdzdWJtaXQnLCBldmVudCA9PiB0aGlzLmZvcm1TdWJtaXRXcmFwcGVyKGV2ZW50KSk7XG4gICAgfVxuICB9XG5cblxuICAvKipcbiAgICogIyBTaG91bGQgbm90IGJlIGNhbGxlZCBkaXJlY3RseSFcbiAgICogVGhpcyBtZXRob2Qgd3JhcHMgdGhlIGZvcm0gdmFsaWRhdGlvbiBhbmQgY2FsbCBbbnJmU3VibWl0XXtAbGluayBOcmZGb3JtRGlyZWN0aXZlI25yZlN1Ym1pdH1cbiAgICovXG4gIEBIb3N0TGlzdGVuZXIoJ3N1Ym1pdCcsIFsnJGV2ZW50J10pXG4gIGZvcm1TdWJtaXRXcmFwcGVyKCRldmVudDogRXZlbnQpIHtcbiAgICAkZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgIGlmICghdGhpcy5mb3JtR3JvdXAudmFsaWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLm5yZlN1Ym1pdC5lbWl0KG5ldyBOcmZTdWJtaXREYXRhKHRoaXMsICRldmVudCkpO1xuICB9XG59XG4iLCJpbXBvcnQgeyBOZ01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybXNNb2R1bGUsIFJlYWN0aXZlRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5cbmltcG9ydCB7IE5yZkZvcm1Db250ZXh0IH0gZnJvbSAnLi9mb3JtLWNvbnRleHQuY2xhc3MnO1xuaW1wb3J0IHsgTnJmU3VibWl0RGF0YSB9IGZyb20gJy4vZm9ybS1zdWJtaXQtZGF0YS5jbGFzcyc7XG5pbXBvcnQgeyBOcmZGb3JtRGlyZWN0aXZlIH0gZnJvbSAnLi9mb3JtLmRpcmVjdGl2ZSc7XG5pbXBvcnQgeyBOUkZfRk9STV9TRVJWSUNFX1BST1ZJREVSLCBOcmZGb3JtU2VydmljZSB9IGZyb20gJy4vZm9ybS5zZXJ2aWNlJztcblxuZXhwb3J0IHsgTnJmRm9ybURpcmVjdGl2ZSwgTnJmRm9ybUNvbnRleHQsIE5yZlN1Ym1pdERhdGEsIE5yZkZvcm1TZXJ2aWNlLCBOUkZfRk9STV9TRVJWSUNFX1BST1ZJREVSIH07XG5cbi8qIHRzbGludDpkaXNhYmxlOiB0ZXItcGFkZGVkLWJsb2NrcyAqL1xuLyoqXG4gKiBUaGlzIG1vZHVsZSBvbmx5IGhhbmRsZSBmb3JtIEFic3RyYWN0aW9uIGFuZCBzdWJtaXQgaGFuZGxlclxuICogTm8gaW5wdXRzIGFyZSBwcm92aWRlZCBieSB0aGlzIG1vZHVsZS5cbiAqL1xuQE5nTW9kdWxlKHtcbiAgaW1wb3J0czogW0Zvcm1zTW9kdWxlLCBSZWFjdGl2ZUZvcm1zTW9kdWxlXSxcbiAgZXhwb3J0czogW0Zvcm1zTW9kdWxlLCBSZWFjdGl2ZUZvcm1zTW9kdWxlLCBOcmZGb3JtRGlyZWN0aXZlXSxcbiAgZGVjbGFyYXRpb25zOiBbTnJmRm9ybURpcmVjdGl2ZV0sXG59KVxuZXhwb3J0IGNsYXNzIE5yZkZvcm1Nb2R1bGUge31cbiIsImltcG9ydCB7IElucHV0LCBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFic3RyYWN0Q29udHJvbE9wdGlvbnMsIFZhbGlkYXRvcnMgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5cbi8qIHRzbGludDpkaXNhYmxlOiB0ZXItcGFkZGVkLWJsb2NrcyAqL1xuXG5leHBvcnQgaW50ZXJmYWNlIE5yZkNvbnRyb2xPcHRpb25zIGV4dGVuZHMgQWJzdHJhY3RDb250cm9sT3B0aW9ucyB7XG4gIGRpc2FibGVkOiBib29sZWFuO1xufVxuXG4vLyB0c2xpbnQ6ZGlzYWJsZSBuby1pbnB1dC1yZW5hbWVcblxuLyoqXG4gKiBJbnB1dCB3cmFwcGVycyBjb21wb25lbnRzIHNob3VsZCBleHRlbmRzIHRoaXMgY2xhc3MgdG8gcGFzcyBjb25zdHJhaW50cyBkb3dud2FyZHNcbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIE5yZkNvbnRyb2xPcHRpb25zQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgLyoqXG4gICAqIEEgbGlzdCBvZiBWYWxpZGF0b3JzIHRvIHZhbGlkYXRlIHRoZSBpbnB1dCBhbmQgdGhlIHVwZGF0ZS1vbiBzdHJhdGVneVxuICAgKi9cbiAgY29udHJvbE9wdGlvbnM6IE5yZkNvbnRyb2xPcHRpb25zO1xuXG4gIC8qKlxuICAgKiBTZXRzIHRoaXMgaW5wdXQgdG8gcmVhZG9ubHkgYW5kIGJsb2NrIGFueSBjaGFuZ2VzXG4gICAqL1xuICBASW5wdXQoJ2Rpc2FibGVkJykgZGlzYWJsZWQ6IGJvb2xlYW4gPSBudWxsO1xuXG4gIC8qKlxuICAgKiBEZWZpbmUgdGhlIGxvd2VzdCBudW1iZXIgdmFsdWUgdGhhdCB0aGlzIGlucHV0IHNob3VsZCBhY2NlcHRcbiAgICovXG4gIEBJbnB1dCgnbWluJykgbWluOiBzdHJpbmcgfCBudW1iZXIgPSBudWxsO1xuXG4gIC8qKlxuICAgKiBEZWZpbmUgdGhlIG1heGltdW0gbnVtYmVyIHZhbHVlIHRoYXQgdGhpcyBpbnB1dCBzaG91bGQgYWNjZXB0XG4gICAqL1xuICBASW5wdXQoJ21heCcpIG1heDogc3RyaW5nIHwgbnVtYmVyID0gbnVsbDtcblxuICAvKipcbiAgICogU2V0IHRoaXMgaW5wdXQgYXMgcmVxdWlyZWQgYW5kIGZhaWxzIHdoZW4gZW1wdHlcbiAgICovXG4gIEBJbnB1dCgncmVxdWlyZWQnKSByZXF1aXJlZDogYm9vbGVhbiA9IG51bGw7XG5cbiAgLy8gQElucHV0KCdSZXF1aXJlZFRydWUnKSByZXF1aXJlZFRydWU6IHN0cmluZyA9IG51bGw7XG5cbiAgLyoqXG4gICAqIFNldCB0aGlzIGlucHV0IGFzIGFuIGUtbWFpbCBhbmQgdmFsaWRhdGVzIHRoZSBlLW1haWwgcGF0dGVyXG4gICAqL1xuICBASW5wdXQoJ2VtYWlsJykgZW1haWw6IGJvb2xlYW4gPSBudWxsO1xuXG4gIC8qKlxuICAgKiBEZWZpbmUgdGhlIG1pbmltdW0gY2hhcmFjdGVycyBxdWFudGl0eSB0aGlzIGlucHV0IHNob3VsZCBhY2NlcHRcbiAgICovXG4gIEBJbnB1dCgnbWluTGVuZ3RoJykgbWluTGVuZ3RoOiBzdHJpbmcgfCBudW1iZXIgPSBudWxsO1xuXG4gIC8qKlxuICAgKiBEZWZpbmUgdGhlIG1heGltdW0gY2hhcmFjdGVycyBxdWFudGl0eSB0aGlzIGlucHV0IHNob3VsZCBhY2NlcHRcbiAgICovXG4gIEBJbnB1dCgnbWF4TGVuZ3RoJykgbWF4TGVuZ3RoOiBzdHJpbmcgfCBudW1iZXIgPSBudWxsO1xuXG4gIC8qKlxuICAgKiBTZXQgYSBSZWd1bGFyIEV4cHJlc3Npb24gdG8gbWF0Y2ggdGhlIGlucHV0IHZhbHVlIGFnYWluc3QgYW5kIGZhaWxzIGlmIG5vdCBtYXRjaFxuICAgKi9cbiAgQElucHV0KCdwYXR0ZXJuJykgcGF0dGVybjogc3RyaW5nIHwgUmVnRXhwID0gbnVsbDtcblxuICAvKipcbiAgICogVGhlIGV2ZW50IG5hbWUgZm9yIGNvbnRyb2wgdG8gdXBkYXRlIHVwb24uXG4gICAqL1xuICBASW5wdXQoJ3VwZGF0ZU9uJykgdXBkYXRlT246ICdjaGFuZ2UnIHwgJ2JsdXInIHwgJ3N1Ym1pdCcgPSBudWxsO1xuXG4gIC8qKlxuICAgKiBDYWNoZSB0aGUgdmFsaWRhdG9ycyB0byBlbmhhbmNlIHRoZSBwZXJmb3JtYW5jZVxuICAgKi9cbiAgbmdPbkluaXQoKSB7XG4gICAgdGhpcy5jb250cm9sT3B0aW9ucyA9IHRoaXMuZ2VuZXJhdGVDb250cm9sT3B0aW9ucygpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIHRoZSBjb250cm9sIG9wdGlvbnMgYmFzZWQgb24gdGhlIHByb3BlcnRpZXMgc2V0IGluIHRoaXMgY29tcG9uZW50XG4gICAqL1xuICBnZW5lcmF0ZUNvbnRyb2xPcHRpb25zKCk6IE5yZkNvbnRyb2xPcHRpb25zIHtcbiAgICByZXR1cm4ge1xuICAgICAgdmFsaWRhdG9yczogT2JqZWN0LmtleXMoVmFsaWRhdG9ycylcbiAgICAgICAgLmZpbHRlcigoa2V5KSA9PiB0aGlzW2tleV0pXG4gICAgICAgIC5tYXAoKGtleSkgPT4gVmFsaWRhdG9yc1trZXldKSxcbiAgICAgIHVwZGF0ZU9uOiB0aGlzLnVwZGF0ZU9uLFxuICAgICAgZGlzYWJsZWQ6IHRoaXMuZGlzYWJsZWQsXG4gICAgfTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgRm9ybUNvbnRyb2wsIEZvcm1Hcm91cCB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcblxuaW1wb3J0IHsgTnJmTmVzdGVkQ29udHJvbERpcmVjdGl2ZSB9IGZyb20gJy4vbmVzdGVkLWNvbnRyb2wuZGlyZWN0aXZlJztcblxuZXhwb3J0IGNsYXNzIE5yZk5lc3RlZENvbnRyb2xDb250ZXh0IHtcbiAgJGltcGxpY2l0OiBGb3JtQ29udHJvbDtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwdWJsaWMgZm9ybUNvbnRyb2w6IEZvcm1Db250cm9sLFxuICAgIHB1YmxpYyBmb3JtR3JvdXA6IEZvcm1Hcm91cCxcbiAgICBwdWJsaWMgbnJmTmVzdGVkQ29udHJvbDogTnJmTmVzdGVkQ29udHJvbERpcmVjdGl2ZSxcbiAgKSB7XG4gICAgdGhpcy4kaW1wbGljaXQgPSBmb3JtQ29udHJvbDtcbiAgfVxufVxuIiwiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybUFycmF5LCBGb3JtQ29udHJvbCwgRm9ybUdyb3VwIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuXG4vKiB0c2xpbnQ6ZGlzYWJsZSB0ZXItcGFkZGVkLWJsb2NrcyAqL1xuXG5ASW5qZWN0YWJsZSgpXG4vKipcbiAqIENvbnRyb2xzIHRoZSBIaWVyYXJjaHkgb2YgRm9ybUdyb3VwcyBhbmQgRm9ybUFycmF5c1xuICovXG5leHBvcnQgY2xhc3MgTnJmRm9ybUhpZXJhcmNoeVNlcnZpY2Uge1xuICAvKipcbiAgICogR2V0IGEgbmVzdGVkIGNvbnRyb2wgaWYgaXQgZXhpc3RzIG9yIGNyZWF0ZSB0aGUgaXRzIG5lY2Vzc2FyeSBoaWVyYXJjaHlcbiAgICpcbiAgICogQHBhcmFtIGZ1bGxQYXRoIERvdCBub3RhdGlvbiBwYXRoIG9mIHRoZSBkZXNpcmVkIGNvbnRyb2wsIGluY2x1ZGluZyB0aGUgbGFzdCBwYXJ0LCB0aGF0IGlzIHRoZSB2YWx1ZSwgbm90IHRoZSBncm91cC5cbiAgICovXG4gIGdldE5lc3RlZENvbnRyb2wocm9vdEZvcm1Hcm91cDogRm9ybUdyb3VwIHwgRm9ybUFycmF5LCBmdWxsUGF0aDogc3RyaW5nIHwgc3RyaW5nW10pOiBGb3JtR3JvdXAgfCBGb3JtQXJyYXkge1xuICAgIGxldCBwYXJlbnRDb250cm9sID0gPEZvcm1Hcm91cCB8IEZvcm1BcnJheT5yb290Rm9ybUdyb3VwLmdldChmdWxsUGF0aCk7XG5cbiAgICBpZiAoIXBhcmVudENvbnRyb2wpIHtcbiAgICAgIGNvbnN0IHBhdGhQaWVjZXMgPSBBcnJheS5pc0FycmF5KGZ1bGxQYXRoKSA/IGZ1bGxQYXRoIDogZnVsbFBhdGguc3BsaXQoJy4nKTtcbiAgICAgIHBhcmVudENvbnRyb2wgPSBwYXRoUGllY2VzLnJlZHVjZTxGb3JtR3JvdXAgfCBGb3JtQXJyYXk+KHRoaXMuY3JlYXRlRm9ybUdyb3VwSGllcmFyY2h5LCByb290Rm9ybUdyb3VwKTtcbiAgICB9XG5cbiAgICBpZiAocGFyZW50Q29udHJvbCBpbnN0YW5jZW9mIEZvcm1Db250cm9sKSB7XG4gICAgICBwYXJlbnRDb250cm9sID0gcGFyZW50Q29udHJvbC5wYXJlbnQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHBhcmVudENvbnRyb2w7XG4gIH1cblxuICAvKipcbiAgICogSXRlcmF0ZSBvdmVyIGFsbCBwYXRoIHBpZWNlcyBjcmVhdGluZyB0aGUgbmVlZGVkIGNvbnRyb2xzIGlmIHRoZXkgZG8gbm90IGV4aXN0cy5cbiAgICovXG4gIHByaXZhdGUgY3JlYXRlRm9ybUdyb3VwSGllcmFyY2h5KFxuICAgIHBhcmVudENvbnRyb2w6IEZvcm1Hcm91cCB8IEZvcm1BcnJheSxcbiAgICBwYXRoOiBzdHJpbmcsXG4gICAgaW5kZXg6IG51bWJlcixcbiAgICBwYXRoUGllY2VzOiBzdHJpbmdbXSxcbiAgKTogRm9ybUdyb3VwIHwgRm9ybUFycmF5IHtcbiAgICBpZiAoaW5kZXggPT09IHBhdGhQaWVjZXMubGVuZ3RoIC0gMSkge1xuICAgICAgcmV0dXJuIHBhcmVudENvbnRyb2w7XG4gICAgfVxuXG4gICAgbGV0IGNvbnRyb2wgPSA8Rm9ybUdyb3VwIHwgRm9ybUFycmF5PnBhcmVudENvbnRyb2wuZ2V0KHBhdGgpO1xuXG4gICAgaWYgKCFjb250cm9sKSB7XG4gICAgICBjb25zdCBuZXh0UGF0aCA9IHBhdGhQaWVjZXNbaW5kZXggKyAxXSB8fCBwYXRoO1xuXG4gICAgICBjb25zdCBpc0FycmF5ID0gbmV4dFBhdGggJiYgIWlzTmFOKDxhbnk+bmV4dFBhdGgpO1xuICAgICAgY29udHJvbCA9IGlzQXJyYXkgPyBuZXcgRm9ybUFycmF5KFtdKSA6IG5ldyBGb3JtR3JvdXAoe30pO1xuICAgIH1cblxuICAgIGlmIChwYXJlbnRDb250cm9sIGluc3RhbmNlb2YgRm9ybUdyb3VwKSB7XG4gICAgICBwYXJlbnRDb250cm9sLmFkZENvbnRyb2wocGF0aCwgY29udHJvbCk7XG4gICAgfSBlbHNlIGlmIChwYXJlbnRDb250cm9sIGluc3RhbmNlb2YgRm9ybUFycmF5KSB7XG4gICAgICBwYXJlbnRDb250cm9sLmluc2VydChwYXJzZUludChwYXRoLCAxMCkgfHwgMCwgY29udHJvbCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNvbnRyb2w7XG4gIH1cbn1cbiIsIi8qISAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5Db3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cclxuTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTsgeW91IG1heSBub3QgdXNlXHJcbnRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlXHJcbkxpY2Vuc2UgYXQgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXHJcblxyXG5USElTIENPREUgSVMgUFJPVklERUQgT04gQU4gKkFTIElTKiBCQVNJUywgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZXHJcbktJTkQsIEVJVEhFUiBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBXSVRIT1VUIExJTUlUQVRJT04gQU5ZIElNUExJRURcclxuV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIFRJVExFLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSxcclxuTUVSQ0hBTlRBQkxJVFkgT1IgTk9OLUlORlJJTkdFTUVOVC5cclxuXHJcblNlZSB0aGUgQXBhY2hlIFZlcnNpb24gMi4wIExpY2Vuc2UgZm9yIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9uc1xyXG5hbmQgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXHJcbi8qIGdsb2JhbCBSZWZsZWN0LCBQcm9taXNlICovXHJcblxyXG52YXIgZXh0ZW5kU3RhdGljcyA9IGZ1bmN0aW9uKGQsIGIpIHtcclxuICAgIGV4dGVuZFN0YXRpY3MgPSBPYmplY3Quc2V0UHJvdG90eXBlT2YgfHxcclxuICAgICAgICAoeyBfX3Byb3RvX186IFtdIH0gaW5zdGFuY2VvZiBBcnJheSAmJiBmdW5jdGlvbiAoZCwgYikgeyBkLl9fcHJvdG9fXyA9IGI7IH0pIHx8XHJcbiAgICAgICAgZnVuY3Rpb24gKGQsIGIpIHsgZm9yICh2YXIgcCBpbiBiKSBpZiAoYi5oYXNPd25Qcm9wZXJ0eShwKSkgZFtwXSA9IGJbcF07IH07XHJcbiAgICByZXR1cm4gZXh0ZW5kU3RhdGljcyhkLCBiKTtcclxufTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2V4dGVuZHMoZCwgYikge1xyXG4gICAgZXh0ZW5kU3RhdGljcyhkLCBiKTtcclxuICAgIGZ1bmN0aW9uIF9fKCkgeyB0aGlzLmNvbnN0cnVjdG9yID0gZDsgfVxyXG4gICAgZC5wcm90b3R5cGUgPSBiID09PSBudWxsID8gT2JqZWN0LmNyZWF0ZShiKSA6IChfXy5wcm90b3R5cGUgPSBiLnByb3RvdHlwZSwgbmV3IF9fKCkpO1xyXG59XHJcblxyXG5leHBvcnQgdmFyIF9fYXNzaWduID0gZnVuY3Rpb24oKSB7XHJcbiAgICBfX2Fzc2lnbiA9IE9iamVjdC5hc3NpZ24gfHwgZnVuY3Rpb24gX19hc3NpZ24odCkge1xyXG4gICAgICAgIGZvciAodmFyIHMsIGkgPSAxLCBuID0gYXJndW1lbnRzLmxlbmd0aDsgaSA8IG47IGkrKykge1xyXG4gICAgICAgICAgICBzID0gYXJndW1lbnRzW2ldO1xyXG4gICAgICAgICAgICBmb3IgKHZhciBwIGluIHMpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocywgcCkpIHRbcF0gPSBzW3BdO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdDtcclxuICAgIH1cclxuICAgIHJldHVybiBfX2Fzc2lnbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19yZXN0KHMsIGUpIHtcclxuICAgIHZhciB0ID0ge307XHJcbiAgICBmb3IgKHZhciBwIGluIHMpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocywgcCkgJiYgZS5pbmRleE9mKHApIDwgMClcclxuICAgICAgICB0W3BdID0gc1twXTtcclxuICAgIGlmIChzICE9IG51bGwgJiYgdHlwZW9mIE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMgPT09IFwiZnVuY3Rpb25cIilcclxuICAgICAgICBmb3IgKHZhciBpID0gMCwgcCA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMocyk7IGkgPCBwLmxlbmd0aDsgaSsrKSBpZiAoZS5pbmRleE9mKHBbaV0pIDwgMClcclxuICAgICAgICAgICAgdFtwW2ldXSA9IHNbcFtpXV07XHJcbiAgICByZXR1cm4gdDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpIHtcclxuICAgIHZhciBjID0gYXJndW1lbnRzLmxlbmd0aCwgciA9IGMgPCAzID8gdGFyZ2V0IDogZGVzYyA9PT0gbnVsbCA/IGRlc2MgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHRhcmdldCwga2V5KSA6IGRlc2MsIGQ7XHJcbiAgICBpZiAodHlwZW9mIFJlZmxlY3QgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIFJlZmxlY3QuZGVjb3JhdGUgPT09IFwiZnVuY3Rpb25cIikgciA9IFJlZmxlY3QuZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpO1xyXG4gICAgZWxzZSBmb3IgKHZhciBpID0gZGVjb3JhdG9ycy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkgaWYgKGQgPSBkZWNvcmF0b3JzW2ldKSByID0gKGMgPCAzID8gZChyKSA6IGMgPiAzID8gZCh0YXJnZXQsIGtleSwgcikgOiBkKHRhcmdldCwga2V5KSkgfHwgcjtcclxuICAgIHJldHVybiBjID4gMyAmJiByICYmIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIGtleSwgciksIHI7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3BhcmFtKHBhcmFtSW5kZXgsIGRlY29yYXRvcikge1xyXG4gICAgcmV0dXJuIGZ1bmN0aW9uICh0YXJnZXQsIGtleSkgeyBkZWNvcmF0b3IodGFyZ2V0LCBrZXksIHBhcmFtSW5kZXgpOyB9XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX21ldGFkYXRhKG1ldGFkYXRhS2V5LCBtZXRhZGF0YVZhbHVlKSB7XHJcbiAgICBpZiAodHlwZW9mIFJlZmxlY3QgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIFJlZmxlY3QubWV0YWRhdGEgPT09IFwiZnVuY3Rpb25cIikgcmV0dXJuIFJlZmxlY3QubWV0YWRhdGEobWV0YWRhdGFLZXksIG1ldGFkYXRhVmFsdWUpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19hd2FpdGVyKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xyXG4gICAgcmV0dXJuIG5ldyAoUCB8fCAoUCA9IFByb21pc2UpKShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7XHJcbiAgICAgICAgZnVuY3Rpb24gZnVsZmlsbGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yW1widGhyb3dcIl0odmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHN0ZXAocmVzdWx0KSB7IHJlc3VsdC5kb25lID8gcmVzb2x2ZShyZXN1bHQudmFsdWUpIDogbmV3IFAoZnVuY3Rpb24gKHJlc29sdmUpIHsgcmVzb2x2ZShyZXN1bHQudmFsdWUpOyB9KS50aGVuKGZ1bGZpbGxlZCwgcmVqZWN0ZWQpOyB9XHJcbiAgICAgICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xyXG4gICAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2dlbmVyYXRvcih0aGlzQXJnLCBib2R5KSB7XHJcbiAgICB2YXIgXyA9IHsgbGFiZWw6IDAsIHNlbnQ6IGZ1bmN0aW9uKCkgeyBpZiAodFswXSAmIDEpIHRocm93IHRbMV07IHJldHVybiB0WzFdOyB9LCB0cnlzOiBbXSwgb3BzOiBbXSB9LCBmLCB5LCB0LCBnO1xyXG4gICAgcmV0dXJuIGcgPSB7IG5leHQ6IHZlcmIoMCksIFwidGhyb3dcIjogdmVyYigxKSwgXCJyZXR1cm5cIjogdmVyYigyKSB9LCB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgKGdbU3ltYm9sLml0ZXJhdG9yXSA9IGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpczsgfSksIGc7XHJcbiAgICBmdW5jdGlvbiB2ZXJiKG4pIHsgcmV0dXJuIGZ1bmN0aW9uICh2KSB7IHJldHVybiBzdGVwKFtuLCB2XSk7IH07IH1cclxuICAgIGZ1bmN0aW9uIHN0ZXAob3ApIHtcclxuICAgICAgICBpZiAoZikgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkdlbmVyYXRvciBpcyBhbHJlYWR5IGV4ZWN1dGluZy5cIik7XHJcbiAgICAgICAgd2hpbGUgKF8pIHRyeSB7XHJcbiAgICAgICAgICAgIGlmIChmID0gMSwgeSAmJiAodCA9IG9wWzBdICYgMiA/IHlbXCJyZXR1cm5cIl0gOiBvcFswXSA/IHlbXCJ0aHJvd1wiXSB8fCAoKHQgPSB5W1wicmV0dXJuXCJdKSAmJiB0LmNhbGwoeSksIDApIDogeS5uZXh0KSAmJiAhKHQgPSB0LmNhbGwoeSwgb3BbMV0pKS5kb25lKSByZXR1cm4gdDtcclxuICAgICAgICAgICAgaWYgKHkgPSAwLCB0KSBvcCA9IFtvcFswXSAmIDIsIHQudmFsdWVdO1xyXG4gICAgICAgICAgICBzd2l0Y2ggKG9wWzBdKSB7XHJcbiAgICAgICAgICAgICAgICBjYXNlIDA6IGNhc2UgMTogdCA9IG9wOyBicmVhaztcclxuICAgICAgICAgICAgICAgIGNhc2UgNDogXy5sYWJlbCsrOyByZXR1cm4geyB2YWx1ZTogb3BbMV0sIGRvbmU6IGZhbHNlIH07XHJcbiAgICAgICAgICAgICAgICBjYXNlIDU6IF8ubGFiZWwrKzsgeSA9IG9wWzFdOyBvcCA9IFswXTsgY29udGludWU7XHJcbiAgICAgICAgICAgICAgICBjYXNlIDc6IG9wID0gXy5vcHMucG9wKCk7IF8udHJ5cy5wb3AoKTsgY29udGludWU7XHJcbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgICAgICAgICAgIGlmICghKHQgPSBfLnRyeXMsIHQgPSB0Lmxlbmd0aCA+IDAgJiYgdFt0Lmxlbmd0aCAtIDFdKSAmJiAob3BbMF0gPT09IDYgfHwgb3BbMF0gPT09IDIpKSB7IF8gPSAwOyBjb250aW51ZTsgfVxyXG4gICAgICAgICAgICAgICAgICAgIGlmIChvcFswXSA9PT0gMyAmJiAoIXQgfHwgKG9wWzFdID4gdFswXSAmJiBvcFsxXSA8IHRbM10pKSkgeyBfLmxhYmVsID0gb3BbMV07IGJyZWFrOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9wWzBdID09PSA2ICYmIF8ubGFiZWwgPCB0WzFdKSB7IF8ubGFiZWwgPSB0WzFdOyB0ID0gb3A7IGJyZWFrOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHQgJiYgXy5sYWJlbCA8IHRbMl0pIHsgXy5sYWJlbCA9IHRbMl07IF8ub3BzLnB1c2gob3ApOyBicmVhazsgfVxyXG4gICAgICAgICAgICAgICAgICAgIGlmICh0WzJdKSBfLm9wcy5wb3AoKTtcclxuICAgICAgICAgICAgICAgICAgICBfLnRyeXMucG9wKCk7IGNvbnRpbnVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIG9wID0gYm9keS5jYWxsKHRoaXNBcmcsIF8pO1xyXG4gICAgICAgIH0gY2F0Y2ggKGUpIHsgb3AgPSBbNiwgZV07IHkgPSAwOyB9IGZpbmFsbHkgeyBmID0gdCA9IDA7IH1cclxuICAgICAgICBpZiAob3BbMF0gJiA1KSB0aHJvdyBvcFsxXTsgcmV0dXJuIHsgdmFsdWU6IG9wWzBdID8gb3BbMV0gOiB2b2lkIDAsIGRvbmU6IHRydWUgfTtcclxuICAgIH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZXhwb3J0U3RhcihtLCBleHBvcnRzKSB7XHJcbiAgICBmb3IgKHZhciBwIGluIG0pIGlmICghZXhwb3J0cy5oYXNPd25Qcm9wZXJ0eShwKSkgZXhwb3J0c1twXSA9IG1bcF07XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3ZhbHVlcyhvKSB7XHJcbiAgICB2YXIgbSA9IHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiBvW1N5bWJvbC5pdGVyYXRvcl0sIGkgPSAwO1xyXG4gICAgaWYgKG0pIHJldHVybiBtLmNhbGwobyk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICAgIG5leHQ6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKG8gJiYgaSA+PSBvLmxlbmd0aCkgbyA9IHZvaWQgMDtcclxuICAgICAgICAgICAgcmV0dXJuIHsgdmFsdWU6IG8gJiYgb1tpKytdLCBkb25lOiAhbyB9O1xyXG4gICAgICAgIH1cclxuICAgIH07XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3JlYWQobywgbikge1xyXG4gICAgdmFyIG0gPSB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgb1tTeW1ib2wuaXRlcmF0b3JdO1xyXG4gICAgaWYgKCFtKSByZXR1cm4gbztcclxuICAgIHZhciBpID0gbS5jYWxsKG8pLCByLCBhciA9IFtdLCBlO1xyXG4gICAgdHJ5IHtcclxuICAgICAgICB3aGlsZSAoKG4gPT09IHZvaWQgMCB8fCBuLS0gPiAwKSAmJiAhKHIgPSBpLm5leHQoKSkuZG9uZSkgYXIucHVzaChyLnZhbHVlKTtcclxuICAgIH1cclxuICAgIGNhdGNoIChlcnJvcikgeyBlID0geyBlcnJvcjogZXJyb3IgfTsgfVxyXG4gICAgZmluYWxseSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgaWYgKHIgJiYgIXIuZG9uZSAmJiAobSA9IGlbXCJyZXR1cm5cIl0pKSBtLmNhbGwoaSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGZpbmFsbHkgeyBpZiAoZSkgdGhyb3cgZS5lcnJvcjsgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIGFyO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19zcHJlYWQoKSB7XHJcbiAgICBmb3IgKHZhciBhciA9IFtdLCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKylcclxuICAgICAgICBhciA9IGFyLmNvbmNhdChfX3JlYWQoYXJndW1lbnRzW2ldKSk7XHJcbiAgICByZXR1cm4gYXI7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2F3YWl0KHYpIHtcclxuICAgIHJldHVybiB0aGlzIGluc3RhbmNlb2YgX19hd2FpdCA/ICh0aGlzLnYgPSB2LCB0aGlzKSA6IG5ldyBfX2F3YWl0KHYpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19hc3luY0dlbmVyYXRvcih0aGlzQXJnLCBfYXJndW1lbnRzLCBnZW5lcmF0b3IpIHtcclxuICAgIGlmICghU3ltYm9sLmFzeW5jSXRlcmF0b3IpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJTeW1ib2wuYXN5bmNJd