ngx-mask-2
Version:
awesome ngx mask
831 lines (821 loc) • 85.9 kB
JavaScript
import { InjectionToken, Inject, Injectable, ElementRef, Renderer2, Directive, forwardRef, HostListener, Input, Pipe, NgModule } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { __awaiter } from 'tslib';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/** @type {?} */
const config = new InjectionToken('config');
/** @type {?} */
const NEW_CONFIG = new InjectionToken('NEW_CONFIG');
/** @type {?} */
const INITIAL_CONFIG = new InjectionToken('INITIAL_CONFIG');
/** @type {?} */
const initialConfig = {
sufix: '',
prefix: '',
clearIfNotMatch: false,
showTemplate: false,
showMaskTyped: false,
dropSpecialCharacters: true,
specialCharacters: ['/', '(', ')', '.', ':', '-', ' ', '+', ',', '@', '[', ']', '\"', '\''],
appendPrefixToModel: false,
patterns: {
'0': {
pattern: new RegExp('\\d'),
},
'9': {
pattern: new RegExp('\\d'),
optional: true
},
'A': {
pattern: new RegExp('\[a-zA-Z0-9\]')
},
'S': {
pattern: new RegExp('\[a-zA-Z\]')
},
'd': {
pattern: new RegExp('\\d'),
},
'm': {
pattern: new RegExp('\\d'),
},
}
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class MaskApplierService {
/**
* @param {?} _config
*/
constructor(_config) {
this._config = _config;
this.maskExpression = '';
this._shift = new Set();
this.maskSpecialCharacters = /** @type {?} */ ((this._config)).specialCharacters;
this.maskAvailablePatterns = this._config.patterns;
this.clearIfNotMatch = this._config.clearIfNotMatch;
this.dropSpecialCharacters = this._config.dropSpecialCharacters;
this.maskSpecialCharacters = /** @type {?} */ ((this._config)).specialCharacters;
this.maskAvailablePatterns = this._config.patterns;
this.prefix = this._config.prefix;
this.sufix = this._config.sufix;
this.appendPrefixToModel = this._config.appendPrefixToModel;
}
/**
* @param {?} inputValue
* @param {?} maskAndPattern
* @return {?}
*/
applyMaskWithPattern(inputValue, maskAndPattern) {
const [mask, customPattern] = maskAndPattern;
this.customPattern = customPattern;
return this.applyMask(inputValue, mask);
}
/**
* @param {?} inputValue
* @param {?} maskExpression
* @param {?=} position
* @param {?=} cb
* @return {?}
*/
applyMask(inputValue, maskExpression, position = 0, cb = () => { }) {
if (inputValue === undefined || inputValue === null || maskExpression === undefined) {
return '';
}
/** @type {?} */
let cursor = 0;
/** @type {?} */
let result = ``;
/** @type {?} */
let multi = false;
if (inputValue.slice(0, this.prefix.length) === this.prefix) {
inputValue = inputValue.slice(this.prefix.length, inputValue.length);
}
/** @type {?} */
const inputArray = inputValue.toString()
.split('');
// tslint:disable-next-line
for (let i = 0, inputSymbol = inputArray[0]; i
< inputArray.length; i++, inputSymbol = inputArray[i]) {
if (cursor === maskExpression.length) {
break;
}
if (this._checkSymbolMask(inputSymbol, maskExpression[cursor]) && maskExpression[cursor + 1] === '?') {
result += inputSymbol;
cursor += 2;
}
else if (maskExpression[cursor + 1] === '*' && multi
&& this._checkSymbolMask(inputSymbol, maskExpression[cursor + 2])) {
result += inputSymbol;
cursor += 3;
multi = false;
}
else if (this._checkSymbolMask(inputSymbol, maskExpression[cursor])
&& maskExpression[cursor + 1]
=== '*') {
result += inputSymbol;
multi = true;
}
else if (maskExpression[cursor + 1] === '?' && this._checkSymbolMask(inputSymbol, maskExpression[cursor + 2])) {
result += inputSymbol;
cursor += 3;
}
else if (this._checkSymbolMask(inputSymbol, maskExpression[cursor])) {
if (maskExpression[cursor] === 'd') {
if (Number(inputSymbol) > 3) {
result += 0;
cursor += 1;
/** @type {?} */
const shiftStep = /\*|\?/g.test(maskExpression.slice(0, cursor))
? inputArray.length
: cursor;
this._shift.add(shiftStep + this.prefix.length || 0);
i--;
continue;
}
}
if (maskExpression[cursor - 1] === 'd') {
if (Number(inputValue.slice(cursor - 1, cursor + 1)) > 31) {
continue;
}
}
if (maskExpression[cursor] === 'm') {
if (Number(inputSymbol) > 1) {
result += 0;
cursor += 1;
/** @type {?} */
const shiftStep = /\*|\?/g.test(maskExpression.slice(0, cursor))
? inputArray.length
: cursor;
this._shift.add(shiftStep + this.prefix.length || 0);
i--;
continue;
}
}
if (maskExpression[cursor - 1] === 'm') {
if (Number(inputValue.slice(cursor - 1, cursor + 1)) > 12) {
continue;
}
}
result += inputSymbol;
cursor++;
}
else if (this.maskSpecialCharacters.indexOf(maskExpression[cursor]) !== -1) {
result += maskExpression[cursor];
cursor++;
/** @type {?} */
const shiftStep = /\*|\?/g.test(maskExpression.slice(0, cursor))
? inputArray.length
: cursor;
this._shift.add(shiftStep + this.prefix.length || 0);
i--;
}
else if (this.maskSpecialCharacters.indexOf(inputSymbol) > -1
&& this.maskAvailablePatterns[maskExpression[cursor]]
&& this.maskAvailablePatterns[maskExpression[cursor]].optional) {
cursor++;
i--;
}
else if ((this.maskExpression[cursor + 1] === '*')
&& (this._findSpecialChar(this.maskExpression[cursor + 2]))
&& (this._findSpecialChar(inputSymbol) === this.maskExpression[cursor + 2])) {
cursor += 3;
result += inputSymbol;
}
}
if (result.length + 1 === maskExpression.length
&& this.maskSpecialCharacters.indexOf(maskExpression[maskExpression.length - 1]) !== -1) {
result += maskExpression[maskExpression.length - 1];
}
/** @type {?} */
let shift = 1;
/** @type {?} */
let newPosition = position + 1;
while (this._shift.has(newPosition)) {
shift++;
newPosition++;
}
cb(this._shift.has(position) ? shift : 0);
/** @type {?} */
let res = `${this.prefix}${result}`;
res = this.sufix &&
cursor === maskExpression.length
? `${this.prefix}${result}${this.sufix}`
: `${this.prefix}${result}`;
return res;
}
/**
* @param {?} inputSymbol
* @return {?}
*/
_findSpecialChar(inputSymbol) {
/** @type {?} */
const symbol = this.maskSpecialCharacters
.find((val) => val === inputSymbol);
return symbol;
}
/**
* @param {?} inputSymbol
* @param {?} maskSymbol
* @return {?}
*/
_checkSymbolMask(inputSymbol, maskSymbol) {
this.maskAvailablePatterns = this.customPattern
? this.customPattern
: this.maskAvailablePatterns;
return this.maskAvailablePatterns[maskSymbol]
&& this.maskAvailablePatterns[maskSymbol].pattern
&& this.maskAvailablePatterns[maskSymbol].pattern.test(inputSymbol);
}
}
MaskApplierService.decorators = [
{ type: Injectable }
];
/** @nocollapse */
MaskApplierService.ctorParameters = () => [
{ type: undefined, decorators: [{ type: Inject, args: [config,] }] }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class MaskService extends MaskApplierService {
/**
* @param {?} document
* @param {?} _config
* @param {?} _elementRef
* @param {?} _renderer
*/
constructor(
// tslint:disable-next-line
document, _config, _elementRef, _renderer) {
super(_config);
this.document = document;
this._config = _config;
this._elementRef = _elementRef;
this._renderer = _renderer;
this.maskExpression = '';
this.isNumberValue = false;
this.showMaskTyped = false;
this.maskIsShown = '';
this.onChange = (_) => { };
this.onTouch = () => { };
this._formElement = this._elementRef.nativeElement;
}
/**
* @param {?} inputValue
* @param {?} maskExpression
* @param {?=} position
* @param {?=} cb
* @return {?}
*/
applyMask(inputValue, maskExpression, position = 0, cb = () => { }) {
this.maskIsShown = this.showMaskTyped
? this.maskExpression.replace(/[0-9]/g, '_')
: '';
if (!inputValue && this.showMaskTyped) {
return this.prefix + this.maskIsShown;
}
/** @type {?} */
const result = super.applyMask(inputValue, maskExpression, position, cb);
/** @type {?} */
let finalResult = Array.isArray(this.dropSpecialCharacters)
? (this._removeMask(this._removeSufix((this.appendPrefixToModel ? result : this._removePrefix(result))), this.dropSpecialCharacters))
: (this.dropSpecialCharacters === true
? (this.isNumberValue
? Number(this._removeMask(this._removeSufix((this.appendPrefixToModel ? result : this._removePrefix(result))), this.maskSpecialCharacters))
: this._removeMask(this._removeSufix((this.appendPrefixToModel ? result : this._removePrefix(result))), this.maskSpecialCharacters))
: (this._removeSufix((this.appendPrefixToModel ? result : this._removePrefix(result)))));
if (this.prefix === finalResult || this.prefix.replace(' ', '') === finalResult
|| this._removeMask(this.prefix, this.maskSpecialCharacters) === finalResult) {
finalResult = '';
}
this.onChange(finalResult);
/** @type {?} */
let ifMaskIsShown = '';
if (!this.showMaskTyped) {
return result;
}
/** @type {?} */
const resLen = result.length;
/** @type {?} */
const prefNmask = this.prefix + this.maskIsShown;
ifMaskIsShown = prefNmask.slice(resLen);
return result + ifMaskIsShown;
}
/**
* @param {?=} position
* @param {?=} cb
* @return {?}
*/
applyValueChanges(position = 0, cb = () => { }) {
/** @type {?} */
const maskedInput = this.applyMask(this._formElement.value, this.maskExpression, position, cb);
this._formElement.value = maskedInput;
if (this._formElement === this.document.activeElement) {
return;
}
this.clearIfNotMatchFn();
}
/**
* @return {?}
*/
showMaskInInput() {
if (this.showMaskTyped) {
this.maskIsShown = this.maskExpression.replace(/[0-9]/g, '_');
}
}
/**
* @return {?}
*/
clearIfNotMatchFn() {
if (this.clearIfNotMatch === true &&
this.maskExpression.length !== this._formElement.value.length) {
this.formElementProperty = ['value', ''];
this.applyMask(this._formElement.value, this.maskExpression);
}
}
/**
* @param {?} __0
* @return {?}
*/
set formElementProperty([name, value]) {
this._renderer.setProperty(this._formElement, name, value);
}
/**
* @param {?} value
* @param {?} specialCharactersForRemove
* @return {?}
*/
_removeMask(value, specialCharactersForRemove) {
return value
? value.replace(this._regExpForRemove(specialCharactersForRemove), '')
: value;
}
/**
* @param {?} value
* @return {?}
*/
_removePrefix(value) {
if (!this.prefix) {
return value;
}
return value
? value.replace(this.prefix, '')
: value;
}
/**
* @param {?} value
* @return {?}
*/
_removeSufix(value) {
if (!this.sufix) {
return value;
}
return value
? value.replace(this.sufix, '')
: value;
}
/**
* @param {?} specialCharactersForRemove
* @return {?}
*/
_regExpForRemove(specialCharactersForRemove) {
return new RegExp(specialCharactersForRemove.map((item) => `\\${item}`).join('|'), 'gi');
}
}
MaskService.decorators = [
{ type: Injectable }
];
/** @nocollapse */
MaskService.ctorParameters = () => [
{ type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
{ type: undefined, decorators: [{ type: Inject, args: [config,] }] },
{ type: ElementRef },
{ type: Renderer2 }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class MaskDirective {
/**
* @param {?} document
* @param {?} _maskService
*/
constructor(
// tslint:disable-next-line
document, _maskService) {
this.document = document;
this._maskService = _maskService;
this._position = null;
this.onChange = (_) => { };
this.onTouch = () => { };
}
/**
* @param {?} value
* @return {?}
*/
set maskExpression(value) {
this._maskValue = value || '';
if (!this._maskValue) {
return;
}
this._maskService.maskExpression = this._repeatPatternSymbols(this._maskValue);
this._maskService.formElementProperty = [
'value',
this._maskService.applyMask(this._inputValue, this._maskService.maskExpression)
];
}
/**
* @param {?} value
* @return {?}
*/
set specialCharacters(value) {
if (!value ||
!Array.isArray(value) ||
(Array.isArray(value) && !value.length)) {
return;
}
this._maskService.maskSpecialCharacters = value;
}
/**
* @param {?} value
* @return {?}
*/
set patterns(value) {
if (!value) {
return;
}
this._maskService.maskAvailablePatterns = value;
}
/**
* @param {?} value
* @return {?}
*/
set prefix(value) {
if (!value) {
return;
}
this._maskService.prefix = value;
}
/**
* @param {?} value
* @return {?}
*/
set sufix(value) {
if (!value) {
return;
}
this._maskService.sufix = value;
}
/**
* @param {?} value
* @return {?}
*/
set dropSpecialCharacters(value) {
this._maskService.dropSpecialCharacters = value;
}
/**
* @param {?} value
* @return {?}
*/
set showMaskTyped(value) {
if (!value) {
return;
}
this._maskService.showMaskTyped = value;
}
/**
* @param {?} value
* @return {?}
*/
set showTemplate(value) {
this._maskService.showTemplate = value;
}
/**
* @param {?} value
* @return {?}
*/
set clearIfNotMatch(value) {
this._maskService.clearIfNotMatch = value;
}
/**
* @param {?} value
* @return {?}
*/
set appendPrefixToModel(value) {
this._maskService.appendPrefixToModel = value;
}
/**
* @param {?} e
* @return {?}
*/
onInput(e) {
/** @type {?} */
const el = /** @type {?} */ (e.target);
this._inputValue = el.value;
if (!this._maskValue) {
this.onChange(el.value);
return;
}
/** @type {?} */
const position = (/** @type {?} */ (el.selectionStart)) === 1
? (/** @type {?} */ (el.selectionStart)) + this._maskService.prefix.length
: /** @type {?} */ (el.selectionStart);
/** @type {?} */
let caretShift = 0;
this._maskService.applyValueChanges(position, (shift) => (caretShift = shift));
// only set the selection if the element is active
if (this.document.activeElement !== el) {
return;
}
el.selectionStart = el.selectionEnd =
this._position !== null
? this._position
: position +
// tslint:disable-next-line
((/** @type {?} */ (e)).inputType === 'deleteContentBackward' ? 0 : caretShift);
this._position = null;
}
/**
* @return {?}
*/
onBlur() {
this._maskService.clearIfNotMatchFn();
this.onTouch();
}
/**
* @param {?} e
* @return {?}
*/
onFocus(e) {
/** @type {?} */
const el = /** @type {?} */ (e.target);
if (el !== null && el.selectionStart !== null &&
el.selectionStart === el.selectionEnd &&
el.selectionStart > this._maskService.prefix.length &&
// tslint:disable-next-line
(/** @type {?} */ (e)).keyCode !== 38) {
return;
}
if (this._maskService.showMaskTyped) {
this._maskService.maskIsShown = this._maskService.maskExpression.replace(/[0-9]/g, '_');
}
el.value = !el.value || el.value === this._maskService.prefix
? this._maskService.prefix + this._maskService.maskIsShown
: el.value;
/** fix of cursor position with prefix when mouse click occur */
if (((/** @type {?} */ (el.selectionStart)) || (/** @type {?} */ (el.selectionEnd))) <= this._maskService.prefix.length) {
el.selectionStart = this._maskService.prefix.length;
return;
}
}
/**
* @param {?} e
* @return {?}
*/
a(e) {
/** @type {?} */
const el = /** @type {?} */ (e.target);
if (e.keyCode === 38) {
e.preventDefault();
}
if (e.keyCode === 37 || e.keyCode === 8) {
if ((/** @type {?} */ (el.selectionStart)) <= this._maskService.prefix.length
&& (/** @type {?} */ (el.selectionEnd)) <= this._maskService.prefix.length) {
e.preventDefault();
}
this.onFocus(e);
if (e.keyCode === 8
&& el.selectionStart === 0
&& el.selectionEnd === el.value.length) {
el.value = this._maskService.prefix;
this._position = this._maskService.prefix ? this._maskService.prefix.length : 1;
this.onInput(e);
}
}
}
/**
* @return {?}
*/
onPaste() {
this._position = Number.MAX_SAFE_INTEGER;
}
/**
* It writes the value in the input
* @param {?} inputValue
* @return {?}
*/
writeValue(inputValue) {
return __awaiter(this, void 0, void 0, function* () {
if (inputValue === undefined) {
inputValue = '';
}
if (inputValue && inputValue.indexOf(this._maskService.prefix) === 0) {
inputValue = inputValue.replace(this._maskService.prefix, '');
}
if (inputValue && inputValue.indexOf(this._maskService.prefix.replace(' ', '')) === 0) {
inputValue = inputValue.replace(this._maskService.prefix.replace(' ', ''), '');
}
if (typeof inputValue === 'number') {
inputValue = String(inputValue);
this._maskService.isNumberValue = true;
}
inputValue && this._maskService.maskExpression ||
this._maskService.maskExpression && (this._maskService.prefix || this._maskService.showMaskTyped)
? (this._maskService.formElementProperty = [
'value',
this._maskService.applyMask(inputValue, this._maskService.maskExpression)
])
: (this._maskService.formElementProperty = ['value', inputValue]);
this._inputValue = inputValue;
});
}
/**
* @param {?} fn
* @return {?}
*/
registerOnChange(fn) {
this.onChange = fn;
this._maskService.onChange = this.onChange;
}
/**
* @param {?} fn
* @return {?}
*/
registerOnTouched(fn) {
this.onTouch = fn;
}
/**
* It disables the input element
* @param {?} isDisabled
* @return {?}
*/
setDisabledState(isDisabled) {
this._maskService.formElementProperty = ['disabled', isDisabled];
}
/**
* @param {?} maskExp
* @return {?}
*/
_repeatPatternSymbols(maskExp) {
return maskExp.match(/{[0-9a-zA-Z]}/)
&& maskExp.split('')
.reduce((accum, currval, index) => {
this._start = (currval === '{') ? index : this._start;
if (currval !== '}') {
return this._maskService._findSpecialChar(currval) ? accum + currval : accum;
}
this._end = index;
/** @type {?} */
const repeatNumber = Number(maskExp
.slice(this._start + 1, this._end));
/** @type {?} */
const repaceWith = new Array(repeatNumber + 1)
.join(maskExp[this._start - 1]);
return accum + repaceWith;
}, '') || maskExp;
}
}
MaskDirective.decorators = [
{ type: Directive, args: [{
selector: '[mask]',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MaskDirective),
multi: true
},
MaskService
]
},] }
];
/** @nocollapse */
MaskDirective.ctorParameters = () => [
{ type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
{ type: MaskService }
];
MaskDirective.propDecorators = {
maskExpression: [{ type: Input, args: ['mask',] }],
specialCharacters: [{ type: Input }],
patterns: [{ type: Input }],
prefix: [{ type: Input }],
sufix: [{ type: Input }],
dropSpecialCharacters: [{ type: Input }],
showMaskTyped: [{ type: Input }],
showTemplate: [{ type: Input }],
clearIfNotMatch: [{ type: Input }],
appendPrefixToModel: [{ type: Input }],
onInput: [{ type: HostListener, args: ['input', ['$event'],] }],
onBlur: [{ type: HostListener, args: ['blur',] }],
onFocus: [{ type: HostListener, args: ['click', ['$event'],] }],
a: [{ type: HostListener, args: ['keydown', ['$event'],] }],
onPaste: [{ type: HostListener, args: ['paste',] }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class MaskPipe {
/**
* @param {?} _maskService
*/
constructor(_maskService) {
this._maskService = _maskService;
}
/**
* @param {?} value
* @param {?} mask
* @return {?}
*/
transform(value, mask) {
if (!value) {
return '';
}
if (typeof mask === 'string') {
return this._maskService.applyMask(`${value}`, mask);
}
return this._maskService.applyMaskWithPattern(`${value}`, mask);
}
}
MaskPipe.decorators = [
{ type: Pipe, args: [{
name: 'mask',
pure: true
},] }
];
/** @nocollapse */
MaskPipe.ctorParameters = () => [
{ type: MaskApplierService }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class NgxMaskModule {
/**
* @param {?=} configValue
* @return {?}
*/
static forRoot(configValue) {
return {
ngModule: NgxMaskModule,
providers: [
{
provide: NEW_CONFIG,
useValue: configValue
},
{
provide: INITIAL_CONFIG,
useValue: initialConfig
},
{
provide: config,
useFactory: _configFactory,
deps: [INITIAL_CONFIG, NEW_CONFIG]
},
]
};
}
/**
* @param {?=} configValue
* @return {?}
*/
static forChild(configValue) {
return {
ngModule: NgxMaskModule,
};
}
}
NgxMaskModule.decorators = [
{ type: NgModule, args: [{
providers: [MaskApplierService],
exports: [MaskDirective, MaskPipe],
declarations: [MaskDirective, MaskPipe]
},] }
];
/**
* \@internal
* @param {?} initConfig
* @param {?} configValue
* @return {?}
*/
function _configFactory(initConfig, configValue) {
return (typeof configValue === 'function') ? configValue() : Object.assign({}, initConfig, configValue);
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
export { config, NEW_CONFIG, INITIAL_CONFIG, initialConfig, MaskDirective, MaskService, _configFactory, NgxMaskModule, MaskPipe, MaskApplierService as ɵa };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LW1hc2stMi5qcy5tYXAiLCJzb3VyY2VzIjpbIm5nOi8vbmd4LW1hc2stMi9hcHAvbmd4LW1hc2svY29uZmlnLnRzIiwibmc6Ly9uZ3gtbWFzay0yL2FwcC9uZ3gtbWFzay9tYXNrLWFwcGxpZXIuc2VydmljZS50cyIsIm5nOi8vbmd4LW1hc2stMi9hcHAvbmd4LW1hc2svbWFzay5zZXJ2aWNlLnRzIiwibmc6Ly9uZ3gtbWFzay0yL2FwcC9uZ3gtbWFzay9tYXNrLmRpcmVjdGl2ZS50cyIsIm5nOi8vbmd4LW1hc2stMi9hcHAvbmd4LW1hc2svbWFzay5waXBlLnRzIiwibmc6Ly9uZ3gtbWFzay0yL2FwcC9uZ3gtbWFzay9uZ3gtbWFzay5tb2R1bGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0aW9uVG9rZW4gfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgSUNvbmZpZyB7XHJcbiAgICBzdWZpeDogc3RyaW5nO1xyXG4gICAgcHJlZml4OiBzdHJpbmc7XHJcbiAgICBjbGVhcklmTm90TWF0Y2g6IGJvb2xlYW47XHJcbiAgICBzaG93VGVtcGxhdGU6IGJvb2xlYW47XHJcbiAgICBzaG93TWFza1R5cGVkOiBib29sZWFuO1xyXG4gICAgZHJvcFNwZWNpYWxDaGFyYWN0ZXJzOiBib29sZWFuIHwgc3RyaW5nW107XHJcbiAgICBzcGVjaWFsQ2hhcmFjdGVyczogc3RyaW5nW107XHJcbiAgICBhcHBlbmRQcmVmaXhUb01vZGVsOiBib29sZWFuO1xyXG4gICAgcGF0dGVybnM6IHtcclxuICAgICAgICBbY2hhcmFjdGVyOiBzdHJpbmddOiB7XHJcbiAgICAgICAgICAgIHBhdHRlcm46IFJlZ0V4cCxcclxuICAgICAgICAgICAgb3B0aW9uYWw/OiBib29sZWFuXHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxufVxyXG5cclxuZXhwb3J0IHR5cGUgb3B0aW9uc0NvbmZpZyA9IFBhcnRpYWw8SUNvbmZpZz47XHJcbmV4cG9ydCBjb25zdCBjb25maWc6IEluamVjdGlvblRva2VuPHN0cmluZz4gPSBuZXcgSW5qZWN0aW9uVG9rZW4oJ2NvbmZpZycpO1xyXG5leHBvcnQgY29uc3QgTkVXX0NPTkZJRzogSW5qZWN0aW9uVG9rZW48c3RyaW5nPiA9IG5ldyBJbmplY3Rpb25Ub2tlbignTkVXX0NPTkZJRycpO1xyXG5leHBvcnQgY29uc3QgSU5JVElBTF9DT05GSUc6IEluamVjdGlvblRva2VuPElDb25maWc+ID0gbmV3IEluamVjdGlvblRva2VuKCdJTklUSUFMX0NPTkZJRycpO1xyXG5cclxuZXhwb3J0IGNvbnN0IGluaXRpYWxDb25maWc6IElDb25maWcgPSB7XHJcbiAgICBzdWZpeDogJycsXHJcbiAgICBwcmVmaXg6ICcnLFxyXG4gICAgY2xlYXJJZk5vdE1hdGNoOiBmYWxzZSxcclxuICAgIHNob3dUZW1wbGF0ZTogZmFsc2UsXHJcbiAgICBzaG93TWFza1R5cGVkOiBmYWxzZSxcclxuICAgIGRyb3BTcGVjaWFsQ2hhcmFjdGVyczogdHJ1ZSxcclxuICAgIHNwZWNpYWxDaGFyYWN0ZXJzOiBbJy8nLCAnKCcsICcpJywgJy4nLCAnOicsICctJywgJyAnLCAnKycsICcsJywgJ0AnLCAnWycsICddJywgJ1xcXCInLCAnXFwnJ10sXHJcbiAgICBhcHBlbmRQcmVmaXhUb01vZGVsOiBmYWxzZSxcclxuICAgIHBhdHRlcm5zOiB7XHJcbiAgICAgICAgJzAnOiB7XHJcbiAgICAgICAgICAgIHBhdHRlcm46IG5ldyBSZWdFeHAoJ1xcXFxkJyksXHJcbiAgICAgICAgfSxcclxuICAgICAgICAnOSc6IHtcclxuICAgICAgICAgICAgcGF0dGVybjogbmV3IFJlZ0V4cCgnXFxcXGQnKSxcclxuICAgICAgICAgICAgb3B0aW9uYWw6IHRydWVcclxuICAgICAgICB9LFxyXG4gICAgICAgICdBJzoge1xyXG4gICAgICAgICAgICBwYXR0ZXJuOiBuZXcgUmVnRXhwKCdcXFthLXpBLVowLTlcXF0nKVxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgJ1MnOiB7XHJcbiAgICAgICAgICAgIHBhdHRlcm46IG5ldyBSZWdFeHAoJ1xcW2EtekEtWlxcXScpXHJcbiAgICAgICAgfSxcclxuICAgICAgICAnZCc6IHtcclxuICAgICAgICAgIHBhdHRlcm46IG5ldyBSZWdFeHAoJ1xcXFxkJyksXHJcbiAgICAgICAgfSxcclxuICAgICAgICAnbSc6IHtcclxuICAgICAgICAgIHBhdHRlcm46IG5ldyBSZWdFeHAoJ1xcXFxkJyksXHJcbiAgICAgICAgfSxcclxuICAgIH1cclxufTtcclxuIiwiaW1wb3J0IHsgSW5qZWN0LCBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IGNvbmZpZywgSUNvbmZpZyB9IGZyb20gJy4vY29uZmlnJztcclxuXHJcbkBJbmplY3RhYmxlKClcclxuZXhwb3J0IGNsYXNzIE1hc2tBcHBsaWVyU2VydmljZSB7XHJcblxyXG4gICAgcHVibGljIGRyb3BTcGVjaWFsQ2hhcmFjdGVyczogSUNvbmZpZ1snZHJvcFNwZWNpYWxDaGFyYWN0ZXJzJ107XHJcbiAgICBwdWJsaWMgc2hvd1RlbXBsYXRlOiBJQ29uZmlnWydzaG93VGVtcGxhdGUnXTtcclxuICAgIHB1YmxpYyBjbGVhcklmTm90TWF0Y2g6IElDb25maWdbJ2NsZWFySWZOb3RNYXRjaCddO1xyXG4gICAgcHVibGljIG1hc2tFeHByZXNzaW9uOiBzdHJpbmcgPSAnJztcclxuICAgIHB1YmxpYyBtYXNrU3BlY2lhbENoYXJhY3RlcnM6IElDb25maWdbJ3NwZWNpYWxDaGFyYWN0ZXJzJ107XHJcbiAgICBwdWJsaWMgbWFza0F2YWlsYWJsZVBhdHRlcm5zOiBJQ29uZmlnWydwYXR0ZXJucyddO1xyXG4gICAgcHVibGljIHByZWZpeDogSUNvbmZpZ1sncHJlZml4J107XHJcbiAgICBwdWJsaWMgc3VmaXg6IElDb25maWdbJ3N1Zml4J107XHJcbiAgICBwdWJsaWMgY3VzdG9tUGF0dGVybjogSUNvbmZpZ1sncGF0dGVybnMnXTtcclxuICAgIHB1YmxpYyBhcHBlbmRQcmVmaXhUb01vZGVsOiBJQ29uZmlnWydhcHBlbmRQcmVmaXhUb01vZGVsJ107XHJcblxyXG5cclxuICAgIHByaXZhdGUgX3NoaWZ0OiBTZXQ8bnVtYmVyPjtcclxuXHJcbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXHJcbiAgICAgICAgQEluamVjdChjb25maWcpIHByb3RlY3RlZCBfY29uZmlnOiBJQ29uZmlnXHJcbiAgICApIHtcclxuICAgICAgICB0aGlzLl9zaGlmdCA9IG5ldyBTZXQoKTtcclxuICAgICAgICB0aGlzLm1hc2tTcGVjaWFsQ2hhcmFjdGVycyA9IHRoaXMuX2NvbmZpZyEuc3BlY2lhbENoYXJhY3RlcnM7XHJcbiAgICAgICAgdGhpcy5tYXNrQXZhaWxhYmxlUGF0dGVybnMgPSB0aGlzLl9jb25maWcucGF0dGVybnM7XHJcbiAgICAgICAgdGhpcy5jbGVhcklmTm90TWF0Y2ggPSB0aGlzLl9jb25maWcuY2xlYXJJZk5vdE1hdGNoO1xyXG4gICAgICAgIHRoaXMuZHJvcFNwZWNpYWxDaGFyYWN0ZXJzID0gdGhpcy5fY29uZmlnLmRyb3BTcGVjaWFsQ2hhcmFjdGVycztcclxuICAgICAgICB0aGlzLm1hc2tTcGVjaWFsQ2hhcmFjdGVycyA9IHRoaXMuX2NvbmZpZyEuc3BlY2lhbENoYXJhY3RlcnM7XHJcbiAgICAgICAgdGhpcy5tYXNrQXZhaWxhYmxlUGF0dGVybnMgPSB0aGlzLl9jb25maWcucGF0dGVybnM7XHJcbiAgICAgICAgdGhpcy5wcmVmaXggPSB0aGlzLl9jb25maWcucHJlZml4O1xyXG4gICAgICAgIHRoaXMuc3VmaXggPSB0aGlzLl9jb25maWcuc3VmaXg7XHJcbiAgICAgICAgdGhpcy5hcHBlbmRQcmVmaXhUb01vZGVsID0gdGhpcy5fY29uZmlnLmFwcGVuZFByZWZpeFRvTW9kZWw7XHJcblxyXG4gICAgfVxyXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWFueVxyXG4gICAgcHVibGljIGFwcGx5TWFza1dpdGhQYXR0ZXJuKGlucHV0VmFsdWU6IHN0cmluZywgbWFza0FuZFBhdHRlcm46IFtzdHJpbmcsIElDb25maWdbJ3BhdHRlcm5zJ11dKTogc3RyaW5nIHtcclxuICAgICAgY29uc3QgW21hc2ssIGN1c3RvbVBhdHRlcm5dID0gbWFza0FuZFBhdHRlcm47XHJcbiAgICAgIHRoaXMuY3VzdG9tUGF0dGVybiA9IGN1c3RvbVBhdHRlcm47XHJcbiAgICAgIHJldHVybiB0aGlzLmFwcGx5TWFzayhpbnB1dFZhbHVlLCBtYXNrKTtcclxuICAgIH1cclxuICAgIHB1YmxpYyBhcHBseU1hc2soXHJcbiAgICAgICAgaW5wdXRWYWx1ZTogc3RyaW5nLFxyXG4gICAgICAgIG1hc2tFeHByZXNzaW9uOiBzdHJpbmcsXHJcbiAgICAgICAgcG9zaXRpb246IG51bWJlciA9IDAsXHJcbiAgICAgICAgY2I6IEZ1bmN0aW9uID0gKCkgPT4ge31cclxuICAgICAgKTogc3RyaW5nIHtcclxuICAgICAgICBpZiAoaW5wdXRWYWx1ZSA9PT0gdW5kZWZpbmVkIHx8IGlucHV0VmFsdWUgPT09IG51bGwgfHwgbWFza0V4cHJlc3Npb24gPT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgICByZXR1cm4gJyc7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBsZXQgY3Vyc29yOiBudW1iZXIgPSAwO1xyXG4gICAgICAgIGxldCByZXN1bHQ6IHN0cmluZyA9IGBgO1xyXG4gICAgICAgIGxldCBtdWx0aTogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICAgICAgICBpZiAoaW5wdXRWYWx1ZS5zbGljZSgwLCB0aGlzLnByZWZpeC5sZW5ndGgpID09PSB0aGlzLnByZWZpeCkge1xyXG4gICAgICAgICAgICBpbnB1dFZhbHVlID0gaW5wdXRWYWx1ZS5zbGljZSh0aGlzLnByZWZpeC5sZW5ndGgsIGlucHV0VmFsdWUubGVuZ3RoKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGNvbnN0IGlucHV0QXJyYXk6IHN0cmluZ1tdID0gaW5wdXRWYWx1ZS50b1N0cmluZygpXHJcbiAgICAgICAgICAgIC5zcGxpdCgnJyk7XHJcblxyXG4gICAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZVxyXG4gICAgICAgIGZvciAobGV0IGk6IG51bWJlciA9IDAsIGlucHV0U3ltYm9sOiBzdHJpbmcgPSBpbnB1dEFycmF5WzBdOyBpXHJcbiAgICAgICAgPCBpbnB1dEFycmF5Lmxlbmd0aDsgaSsrLCBpbnB1dFN5bWJvbCA9IGlucHV0QXJyYXlbaV0pIHtcclxuICAgICAgICAgICAgaWYgKGN1cnNvciA9PT0gbWFza0V4cHJlc3Npb24ubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBpZiAodGhpcy5fY2hlY2tTeW1ib2xNYXNrKGlucHV0U3ltYm9sLCBtYXNrRXhwcmVzc2lvbltjdXJzb3JdKSAmJiBtYXNrRXhwcmVzc2lvbltjdXJzb3IgKyAxXSA9PT0gJz8nKSB7XHJcbiAgICAgICAgICAgICAgICByZXN1bHQgKz0gaW5wdXRTeW1ib2w7XHJcbiAgICAgICAgICAgICAgICBjdXJzb3IgKz0gMjtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChcclxuICAgICAgICAgICAgICBtYXNrRXhwcmVzc2lvbltjdXJzb3IgKyAxXSA9PT0gJyonICYmIG11bHRpXHJcbiAgICAgICAgICAgICAgJiYgdGhpcy5fY2hlY2tTeW1ib2xNYXNrKGlucHV0U3ltYm9sLCBtYXNrRXhwcmVzc2lvbltjdXJzb3IgKyAyXSlcclxuICAgICAgICAgICAgKSB7XHJcbiAgICAgICAgICAgICAgcmVzdWx0ICs9IGlucHV0U3ltYm9sO1xyXG4gICAgICAgICAgICAgIGN1cnNvciArPSAzO1xyXG4gICAgICAgICAgICAgIG11bHRpID0gZmFsc2U7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5fY2hlY2tTeW1ib2xNYXNrKGlucHV0U3ltYm9sLCBtYXNrRXhwcmVzc2lvbltjdXJzb3JdKVxyXG4gICAgICAgICAgICAgICAgJiYgbWFza0V4cHJlc3Npb25bY3Vyc29yICsgMV1cclxuICAgICAgICAgICAgICAgID09PSAnKicpIHtcclxuICAgICAgICAgICAgICAgIHJlc3VsdCArPSBpbnB1dFN5bWJvbDtcclxuICAgICAgICAgICAgICAgIG11bHRpID0gdHJ1ZTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChtYXNrRXhwcmVzc2lvbltjdXJzb3IgKyAxXSA9PT0gJz8nICYmIHRoaXMuX2NoZWNrU3ltYm9sTWFzayhcclxuICAgICAgICAgICAgICAgIGlucHV0U3ltYm9sLFxyXG4gICAgICAgICAgICAgICAgbWFza0V4cHJlc3Npb25bY3Vyc29yICsgMl1cclxuICAgICAgICAgICAgKSkge1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0ICs9IGlucHV0U3ltYm9sO1xyXG4gICAgICAgICAgICAgICAgY3Vyc29yICs9IDM7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5fY2hlY2tTeW1ib2xNYXNrKGlucHV0U3ltYm9sLCBtYXNrRXhwcmVzc2lvbltjdXJzb3JdKSkge1xyXG4gICAgICAgICAgICAgICAgaWYgKG1hc2tFeHByZXNzaW9uW2N1cnNvcl0gPT09ICdkJykge1xyXG4gICAgICAgICAgICAgICAgICBpZiAoTnVtYmVyKGlucHV0U3ltYm9sKSA+IDMpIHtcclxuICAgICAgICAgICAgICAgICAgICByZXN1bHQgKz0gMDtcclxuICAgICAgICAgICAgICAgICAgICBjdXJzb3IgKz0gMTtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCBzaGlmdFN0ZXA6IG51bWJlciA9IC9cXCp8XFw/L2cudGVzdChtYXNrRXhwcmVzc2lvbi5zbGljZSgwLCBjdXJzb3IpKVxyXG4gICAgICAgICAgICAgICAgICAgICAgPyBpbnB1dEFycmF5Lmxlbmd0aFxyXG4gICAgICAgICAgICAgICAgICAgICAgOiBjdXJzb3I7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fc2hpZnQuYWRkKCBzaGlmdFN0ZXAgKyB0aGlzLnByZWZpeC5sZW5ndGggfHwgMCk7XHJcbiAgICAgICAgICAgICAgICAgICAgaS0tO1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgaWYgKG1hc2tFeHByZXNzaW9uW2N1cnNvciAtIDFdID09PSAnZCcpIHtcclxuICAgICAgICAgICAgICAgICAgaWYgKE51bWJlcihpbnB1dFZhbHVlLnNsaWNlKGN1cnNvciAtIDEsIGN1cnNvciArIDEpKSA+IDMxICkge1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIGlmIChtYXNrRXhwcmVzc2lvbltjdXJzb3JdID09PSAnbScpIHtcclxuICAgICAgICAgICAgICAgIGlmIChOdW1iZXIoaW5wdXRTeW1ib2wpID4gMSkge1xyXG4gICAgICAgICAgICAgICAgICByZXN1bHQgKz0gMDtcclxuICAgICAgICAgICAgICAgICAgY3Vyc29yICs9IDE7XHJcbiAgICAgICAgICAgICAgICAgIGNvbnN0IHNoaWZ0U3RlcDogbnVtYmVyID0gL1xcKnxcXD8vZy50ZXN0KG1hc2tFeHByZXNzaW9uLnNsaWNlKDAsIGN1cnNvcikpXHJcbiAgICAgICAgICAgICAgICAgICAgPyBpbnB1dEFycmF5Lmxlbmd0aFxyXG4gICAgICAgICAgICAgICAgICAgIDogY3Vyc29yO1xyXG4gICAgICAgICAgICAgICAgICB0aGlzLl9zaGlmdC5hZGQoIHNoaWZ0U3RlcCArIHRoaXMucHJlZml4Lmxlbmd0aCB8fCAwKTtcclxuICAgICAgICAgICAgICAgICAgaS0tO1xyXG4gICAgICAgICAgICAgICAgICBjb250aW51ZTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgaWYgKG1hc2tFeHByZXNzaW9uW2N1cnNvciAtIDFdID09PSAnbScpIHtcclxuICAgICAgICAgICAgICAgIGlmIChOdW1iZXIoaW5wdXRWYWx1ZS5zbGljZShjdXJzb3IgLSAxLCBjdXJzb3IgKyAxKSkgPiAxMiApIHtcclxuICAgICAgICAgICAgICAgICAgY29udGludWU7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgcmVzdWx0ICs9IGlucHV0U3ltYm9sO1xyXG4gICAgICAgICAgICAgICAgY3Vyc29yKys7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5tYXNrU3BlY2lhbENoYXJhY3RlcnMuaW5kZXhPZihtYXNrRXhwcmVzc2lvbltjdXJzb3JdKSAhPT0gLTEpIHtcclxuICAgICAgICAgICAgICAgIHJlc3VsdCArPSBtYXNrRXhwcmVzc2lvbltjdXJzb3JdO1xyXG4gICAgICAgICAgICAgICAgY3Vyc29yKys7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBzaGlmdFN0ZXA6IG51bWJlciA9IC9cXCp8XFw/L2cudGVzdChtYXNrRXhwcmVzc2lvbi5zbGljZSgwLCBjdXJzb3IpKVxyXG4gICAgICAgICAgICAgICAgICAgID8gaW5wdXRBcnJheS5sZW5ndGhcclxuICAgICAgICAgICAgICAgICAgICA6IGN1cnNvcjtcclxuICAgICAgICAgICAgICAgIHRoaXMuX3NoaWZ0LmFkZChzaGlmdFN0ZXAgKyB0aGlzLnByZWZpeC5sZW5ndGggfHwgMCk7XHJcbiAgICAgICAgICAgICAgICBpLS07XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5tYXNrU3BlY2lhbENoYXJhY3RlcnMuaW5kZXhPZihpbnB1dFN5bWJvbCkgPiAtMVxyXG4gICAgICAgICAgICAgICAgJiYgdGhpcy5tYXNrQXZhaWxhYmxlUGF0dGVybnNbbWFza0V4cHJlc3Npb25bY3Vyc29yXV1cclxuICAgICAgICAgICAgICAgICYmIHRoaXMubWFza0F2YWlsYWJsZVBhdHRlcm5zW21hc2tFeHByZXNzaW9uW2N1cnNvcl1dLm9wdGlvbmFsKSB7XHJcbiAgICAgICAgICAgICAgICBjdXJzb3IrKztcclxuICAgICAgICAgICAgICAgIGktLTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmICggKHRoaXMubWFza0V4cHJlc3Npb25bY3Vyc29yICsgMV0gPT09ICcqJylcclxuICAgICAgICAgICAgICAmJiAodGhpcy5fZmluZFNwZWNpYWxDaGFyKHRoaXMubWFza0V4cHJlc3Npb25bY3Vyc29yICsgMl0pKVxyXG4gICAgICAgICAgICAgICYmICh0aGlzLl9maW5kU3BlY2lhbENoYXIoaW5wdXRTeW1ib2wpID09PSB0aGlzLm1hc2tFeHByZXNzaW9uW2N1cnNvciArIDJdKSApIHtcclxuICAgICAgICAgICAgICBjdXJzb3IgKz0gMztcclxuICAgICAgICAgICAgICByZXN1bHQgKz0gaW5wdXRTeW1ib2w7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG5cclxuICAgICAgICBpZiAocmVzdWx0Lmxlbmd0aCArIDEgPT09IG1hc2tFeHByZXNzaW9uLmxlbmd0aFxyXG4gICAgICAgICAgICAmJiB0aGlzLm1hc2tTcGVjaWFsQ2hhcmFjdGVycy5pbmRleE9mKG1hc2tFeHByZXNzaW9uW21hc2tFeHByZXNzaW9uLmxlbmd0aCAtIDFdKSAhPT0gLTEpIHtcclxuICAgICAgICAgICAgcmVzdWx0ICs9IG1hc2tFeHByZXNzaW9uW21hc2tFeHByZXNzaW9uLmxlbmd0aCAtIDFdO1xyXG4gICAgICAgIH1cclxuXHJcblxyXG4gICAgICAgIGxldCBzaGlmdDogbnVtYmVyID0gMTtcclxuICAgICAgICBsZXQgbmV3UG9zaXRpb246IG51bWJlciA9IHBvc2l0aW9uICsgMTtcclxuXHJcbiAgICAgICAgd2hpbGUgKHRoaXMuX3NoaWZ0LmhhcyhuZXdQb3NpdGlvbikpIHtcclxuICAgICAgICAgICAgc2hpZnQrKztcclxuICAgICAgICAgICAgbmV3UG9zaXRpb24rKztcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGNiKHRoaXMuX3NoaWZ0Lmhhcyhwb3NpdGlvbikgPyBzaGlmdCA6IDApO1xyXG4gICAgICAgIGxldCByZXM6IHN0cmluZyA9IGAke3RoaXMucHJlZml4fSR7cmVzdWx0fWA7XHJcbiAgICAgICAgcmVzID0gdGhpcy5zdWZpeCAmJlxyXG4gICAgICAgICAgICAgIGN1cnNvciA9PT0gbWFza0V4cHJlc3Npb24ubGVuZ3RoXHJcbiAgICAgICAgICAgID8gYCR7dGhpcy5wcmVmaXh9JHtyZXN1bHR9JHt0aGlzLnN1Zml4fWBcclxuICAgICAgICAgICAgOiBgJHt0aGlzLnByZWZpeH0ke3Jlc3VsdH1gO1xyXG4gICAgICAgIHJldHVybiByZXM7XHJcbiAgICB9XHJcbiAgICBwdWJsaWMgX2ZpbmRTcGVjaWFsQ2hhciAoaW5wdXRTeW1ib2w6IHN0cmluZyk6IHVuZGVmaW5lZCB8IHN0cmluZyB7XHJcbiAgICAgIGNvbnN0IHN5bWJvbDogc3RyaW5nIHwgdW5kZWZpbmVkID0gdGhpcy5tYXNrU3BlY2lhbENoYXJhY3RlcnNcclxuICAgICAgICAgIC5maW5kKCAodmFsOiBzdHJpbmcpID0+IHZhbCA9PT0gaW5wdXRTeW1ib2wpO1xyXG4gICAgICByZXR1cm4gc3ltYm9sIDtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIF9jaGVja1N5bWJvbE1hc2soaW5wdXRTeW1ib2w6IHN0cmluZywgbWFza1N5bWJvbDogc3RyaW5nKTogYm9vbGVhbiB7XHJcbiAgICAgIHRoaXMubWFza0F2YWlsYWJsZVBhdHRlcm5zID0gdGhpcy5jdXN0b21QYXR0ZXJuXHJcbiAgICAgICAgPyB0aGlzLmN1c3RvbVBhdHRlcm5cclxuICAgICAgICA6IHRoaXMubWFza0F2YWlsYWJsZVBhdHRlcm5zO1xyXG4gICAgICAgIHJldHVybiB0aGlzLm1hc2tBdmFpbGFibGVQYXR0ZXJuc1ttYXNrU3ltYm9sXVxyXG4gICAgICAgICAgICAmJiB0aGlzLm1hc2tBdmFpbGFibGVQYXR0ZXJuc1ttYXNrU3ltYm9sXS5wYXR0ZXJuXHJcbiAgICAgICAgICAgICYmIHRoaXMubWFza0F2YWlsYWJsZVBhdHRlcm5zW21hc2tTeW1ib2xdLnBhdHRlcm4udGVzdChpbnB1dFN5bWJvbCk7XHJcbiAgICB9XHJcbn1cclxuIiwiaW1wb3J0IHsgRWxlbWVudFJlZiwgSW5qZWN0LCBJbmplY3RhYmxlLCBSZW5kZXJlcjIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgY29uZmlnLCBJQ29uZmlnIH0gZnJvbSAnLi9jb25maWcnO1xyXG5pbXBvcnQgeyBET0NVTUVOVCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IE1hc2tBcHBsaWVyU2VydmljZSB9IGZyb20gJy4vbWFzay1hcHBsaWVyLnNlcnZpY2UnO1xyXG5cclxuQEluamVjdGFibGUoKVxyXG5leHBvcnQgY2xhc3MgTWFza1NlcnZpY2UgZXh0ZW5kcyBNYXNrQXBwbGllclNlcnZpY2Uge1xyXG4gIHB1YmxpYyBtYXNrRXhwcmVzc2lvbjogc3RyaW5nID0gJyc7XHJcbiAgcHVibGljIGlzTnVtYmVyVmFsdWU6IGJvb2xlYW4gPSBmYWxzZTtcclxuICBwdWJsaWMgc2hvd01hc2tUeXBlZDogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIHB1YmxpYyBtYXNrSXNTaG93bjogc3RyaW5nID0gJyc7XHJcbiAgcHJpdmF0ZSBfZm9ybUVsZW1lbnQ6IEhUTUxJbnB1dEVsZW1lbnQ7XHJcbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lXHJcbiAgcHVibGljIG9uQ2hhbmdlID0gKF86IGFueSkgPT4ge307XHJcbiAgcHVibGljIG9uVG91Y2ggPSAoKSA9PiB7fTtcclxuICBwdWJsaWMgY29uc3RydWN0b3IoXHJcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmVcclxuICAgIEBJbmplY3QoRE9DVU1FTlQpIHByaXZhdGUgZG9jdW1lbnQ6IGFueSxcclxuICAgIEBJbmplY3QoY29uZmlnKSBwcm90ZWN0ZWQgX2NvbmZpZzogSUNvbmZpZyxcclxuICAgIHByaXZhdGUgX2VsZW1lbnRSZWY6IEVsZW1lbnRSZWYsXHJcbiAgICBwcml2YXRlIF9yZW5kZXJlcjogUmVuZGVyZXIyXHJcbiAgKSB7XHJcbiAgICBzdXBlcihfY29uZmlnKTtcclxuICAgIHRoaXMuX2Zvcm1FbGVtZW50ID0gdGhpcy5fZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50O1xyXG4gIH1cclxuXHJcbiAgcHVibGljIGFwcGx5TWFzayhcclxuICAgIGlucHV0VmFsdWU6IHN0cmluZyxcclxuICAgIG1hc2tFeHByZXNzaW9uOiBzdHJpbmcsXHJcbiAgICBwb3NpdGlvbjogbnVtYmVyID0gMCxcclxuICAgIGNiOiBGdW5jdGlvbiA9ICgpID0+IHt9XHJcbiAgKTogc3RyaW5nICB7XHJcbiAgICB0aGlzLm1hc2tJc1Nob3duID0gdGhpcy5zaG93TWFza1R5cGVkXHJcbiAgICAgICAgPyB0aGlzLm1hc2tFeHByZXNzaW9uLnJlcGxhY2UoL1swLTldL2csICdfJylcclxuICAgICAgICA6ICcnO1xyXG4gICAgaWYgKCFpbnB1dFZhbHVlICYmIHRoaXMuc2hvd01hc2tUeXBlZCkge1xyXG4gICAgICByZXR1cm4gdGhpcy5wcmVmaXggKyB0aGlzLm1hc2tJc1Nob3duO1xyXG4gICAgfVxyXG4gICAgY29uc3QgcmVzdWx0OiBzdHJpbmcgID0gc3VwZXIuYXBwbHlNYXNrKFxyXG4gICAgICBpbnB1dFZhbHVlLFxyXG4gICAgICBtYXNrRXhwcmVzc2lvbixcclxuICAgICAgcG9zaXRpb24sXHJcbiAgICAgIGNiXHJcbiAgICApO1xyXG5cclxuICAgIGxldCBmaW5hbFJlc3VsdDogc3RyaW5nIHwgbnVtYmVyID0gQXJyYXkuaXNBcnJheSh0aGlzLmRyb3BTcGVjaWFsQ2hhcmFjdGVycylcclxuICAgICAgICA/ICh0aGlzLl9yZW1vdmVNYXNrKHRoaXMuX3JlbW92ZVN1Zml4KFxyXG4gICAgICAgICh0aGlzLmFwcGVuZFByZWZpeFRvTW9kZWwgPyByZXN1bHQgOiB0aGlzLl9yZW1vdmVQcmVmaXgocmVzdWx0KSlcclxuICAgICAgICApLCB0aGlzLmRyb3BTcGVjaWFsQ2hhcmFjdGVycykpXHJcbiAgICAgICAgOiAodGhpcy5kcm9wU3BlY2lhbENoYXJhY3RlcnMgPT09IHRydWVcclxuICAgICAgICAgPyAoXHJcbiAgICAgICAgIHRoaXMuaXNOdW1iZXJWYWx1ZVxyXG4gICAgICAgICAgICAgPyBOdW1iZXIodGhpcy5fcmVtb3ZlTWFzayh0aGlzLl9yZW1vdmVTdWZpeChcclxuICAgICAgICAgICAgICh0aGlzLmFwcGVuZFByZWZpeFRvTW9kZWwgPyByZXN1bHQgOiB0aGlzLl9yZW1vdmVQcmVmaXgocmVzdWx0KSkpLCB0aGlzLm1hc2tTcGVjaWFsQ2hhcmFjdGVycykpXHJcbiAgICAgICAgICAgICA6IHRoaXMuX3JlbW92ZU1hc2sodGhpcy5fcmVtb3ZlU3VmaXgoXHJcbiAgICAgICAgICAgICAodGhpcy5hcHBlbmRQcmVmaXhUb01vZGVsID8gcmVzdWx0IDogdGhpcy5fcmVtb3ZlUHJlZml4KHJlc3VsdCkpKSwgdGhpcy5tYXNrU3BlY2lhbENoYXJhY3RlcnMpXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICAgOiAodGhpcy5fcmVtb3ZlU3VmaXgoKHRoaXMuYXBwZW5kUHJlZml4VG9Nb2RlbCA/IHJlc3VsdCA6IHRoaXMuX3JlbW92ZVByZWZpeChyZXN1bHQpKSkpKTtcclxuXHJcbiAgICBpZiAodGhpcy5wcmVmaXggPT09IGZpbmFsUmVzdWx0IHx8IHRoaXMucHJlZml4LnJlcGxhY2UoJyAnLCAnJykgPT09IGZpbmFsUmVzdWx0XHJcbiAgICAgICAgfHwgdGhpcy5fcmVtb3ZlTWFzayh0aGlzLnByZWZpeCwgdGhpcy5tYXNrU3BlY2lhbENoYXJhY3RlcnMpID09PSBmaW5hbFJlc3VsdCkge1xyXG4gICAgICAgIGZpbmFsUmVzdWx0ID0gJyc7XHJcbiAgICB9XHJcbiAgICB0aGlzLm9uQ2hhbmdlKGZpbmFsUmVzdWx0KTtcclxuXHJcbiAgICBsZXQgaWZNYXNrSXNTaG93bjogc3RyaW5nID0gJyc7XHJcbiAgICBpZiAoIXRoaXMuc2hvd01hc2tUeXBlZCkge1xyXG4gICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICB9XHJcbiAgICBjb25zdCByZXNMZW46IG51bWJlciA9IHJlc3VsdC5sZW5ndGg7XHJcbiAgICBjb25zdCBwcmVmTm1hc2s6IHN0cmluZyA9IHRoaXMucHJlZml4ICsgdGhpcy5tYXNrSXNTaG93bjtcclxuICAgIGlmTWFza0lzU2hvd24gPSBwcmVmTm1hc2suc2xpY2UocmVzTGVuKTtcclxuXHJcbiAgICByZXR1cm4gcmVzdWx0ICsgaWZNYXNrSXNTaG93bjtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBhcHBseVZhbHVlQ2hhbmdlcyhcclxuICAgIHBvc2l0aW9uOiBudW1iZXIgPSAwLFxyXG4gICAgY2I6IEZ1bmN0aW9uID0gKCkgPT4ge31cclxuICApOiB2b2lkIHtcclxuICAgIGNvbnN0IG1hc2tlZElucHV0OiBzdHJpbmcgfCBudW1iZXIgPSB0aGlzLmFwcGx5TWFzayhcclxuICAgICAgdGhpcy5fZm9ybUVsZW1lbnQudmFsdWUsXHJcbiAgICAgIHRoaXMubWFza0V4cHJlc3Npb24sXHJcbiAgICAgIHBvc2l0aW9uLFxyXG4gICAgICBjYlxyXG4gICAgKTtcclxuXHJcbiAgICB0aGlzLl9mb3JtRWxlbWVudC52YWx1ZSA9IG1hc2tlZElucHV0O1xyXG4gICAgaWYgKHRoaXMuX2Zvcm1FbGVtZW50ID09PSB0aGlzLmRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgdGhpcy5jbGVhcklmTm90TWF0Y2hGbigpO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIHNob3dNYXNrSW5JbnB1dCgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLnNob3dNYXNrVHlwZWQpIHtcclxuICAgICAgdGhpcy5tYXNrSXNTaG93biA9IHRoaXMubWFza0V4cHJlc3Npb24ucmVwbGFjZSgvWzAtOV0vZywgJ18nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHB1YmxpYyBjbGVhcklmTm90TWF0Y2hGbigpOiB2b2lkIHtcclxuICAgIGlmIChcclxuICAgICAgdGhpcy5jbGVhcklmTm90TWF0Y2ggPT09IHRydWUgJiZcclxuICAgICAgdGhpcy5tYXNrRXhwcmVzc2lvbi5sZW5ndGggIT09IHRoaXMuX2Zvcm1FbGVtZW50LnZhbHVlLmxlbmd0aFxyXG4gICAgKSB7XHJcbiAgICAgIHRoaXMuZm9ybUVsZW1lbnRQcm9wZXJ0eSA9IFsndmFsdWUnLCAnJ107XHJcbiAgICAgIHRoaXMuYXBwbHlNYXNrKHRoaXMuX2Zvcm1FbGVtZW50LnZhbHVlLCB0aGlzLm1hc2tFeHByZXNzaW9uKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHB1YmxpYyBzZXQgZm9ybUVsZW1lbnRQcm9wZXJ0eShbbmFtZSwgdmFsdWVdOiBbc3RyaW5nLCBzdHJpbmcgfCBib29sZWFuXSkge1xyXG4gICAgdGhpcy5fcmVuZGVyZXIuc2V0UHJvcGVydHkodGhpcy5fZm9ybUVsZW1lbnQsIG5hbWUsIHZhbHVlKTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBfcmVtb3ZlTWFzayhcclxuICAgIHZhbHVlOiBzdHJpbmcsXHJcbiAgICBzcGVjaWFsQ2hhcmFjdGVyc0ZvclJlbW92ZTogc3RyaW5nW11cclxuICApOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHZhbHVlXHJcbiAgICAgID8gdmFsdWUucmVwbGFjZSh0aGlzLl9yZWdFeHBGb3JSZW1vdmUoc3BlY2lhbENoYXJhY3RlcnNGb3JSZW1vdmUpLCAnJylcclxuICAgICAgOiB2YWx1ZTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBfcmVtb3ZlUHJlZml4KHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgaWYgKCF0aGlzLnByZWZpeCkge1xyXG4gICAgICByZXR1cm4gdmFsdWU7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdmFsdWVcclxuICAgICAgPyB2YWx1ZS5yZXBsYWNlKHRoaXMucHJlZml4LCAnJylcclxuICAgICAgOiB2YWx1ZTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgX3JlbW92ZVN1Zml4KHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgaWYgKCF0aGlzLnN1Zml4KSB7XHJcbiAgICAgIHJldHVybiB2YWx1ZTtcclxuICAgIH1cclxuICAgIHJldHVybiB2YWx1ZVxyXG4gICAgICA/IHZhbHVlLnJlcGxhY2UodGhpcy5zdWZpeCwgJycpXHJcbiAgICAgIDogdmFsdWU7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIF9yZWdFeHBGb3JSZW1vdmUoc3BlY2lhbENoYXJhY3RlcnNGb3JSZW1vdmU6IHN0cmluZ1tdKTogUmVnRXhwIHtcclxuICAgIHJldHVybiBuZXcgUmVnRXhwKFxyXG4gICAgICBzcGVjaWFsQ2hhcmFjdGVyc0ZvclJlbW92ZS5tYXAoKGl0ZW06IHN0cmluZykgPT4gYFxcXFwke2l0ZW19YCkuam9pbignfCcpLFxyXG4gICAgICAnZ2knXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG4iLCJpbXBvcnQge1xyXG4gIERpcmVjdGl2ZSxcclxuICBmb3J3YXJkUmVmLFxyXG4gIEhvc3RMaXN0ZW5lcixcclxuICBJbmplY3QsXHJcbiAgSW5wdXRcclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgRE9DVU1FTlQgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgTkdfVkFMVUVfQUNDRVNTT1IgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7IE1hc2tTZXJ2aWNlIH0gZnJvbSAnLi9tYXNrLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBJQ29uZmlnIH0gZnJvbSAnLi9jb25maWcnO1xyXG5cclxuQERpcmVjdGl2ZSh7XHJcbiAgc2VsZWN0b3I6ICdbbWFza10nLFxyXG4gIHByb3ZpZGVyczogW1xyXG4gICAge1xyXG4gICAgICBwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcclxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gTWFza0RpcmVjdGl2ZSksXHJcbiAgICAgIG11bHRpOiB0cnVlXHJcbiAgICB9LFxyXG4gICAgTWFza1NlcnZpY2VcclxuICBdXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBNYXNrRGlyZWN0aXZlIGltcGxlbWVudHMgQ29udHJvbFZhbHVlQWNjZXNzb3Ige1xyXG4gIHByaXZhdGUgX21hc2tWYWx1ZTogc3RyaW5nO1xyXG4gIHByaXZhdGUgX2lucHV0VmFsdWU6IHN0cmluZztcclxuICBwcml2YXRlIF9wb3NpdGlvbjogbnVtYmVyIHwgbnVsbCA9IG51bGw7XHJcbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lXHJcbiAgcHJpdmF0ZSBfc3RhcnQ6IG51bWJlcjtcclxuICBwcml2YXRlIF9lbmQ6IG51bWJlcjtcclxuICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmVcclxuICBwdWJsaWMgb25DaGFuZ2UgPSAoXzogYW55KSA9PiB7IH07XHJcbiAgcHVibGljIG9uVG91Y2ggPSAoKSA9PiB7IH07XHJcbiAgcHVibGljIGNvbnN0cnVjdG9yKFxyXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lXHJcbiAgICBASW5qZWN0KERPQ1VNRU5UKSBwcml2YXRlIGRvY3VtZW50OiBhbnksXHJcbiAgICBwcml2YXRlIF9tYXNrU2VydmljZTogTWFza1NlcnZpY2VcclxuICApIHsgfVxyXG5cclxuXHJcbiAgQElucHV0KCdtYXNrJylcclxuICBwdWJsaWMgc2V0IG1hc2tFeHByZXNzaW9uKHZhbHVlOiBzdHJpbmcpIHtcclxuICAgIHRoaXMuX21hc2tWYWx1ZSA9IHZhbHVlIHx8ICcnO1xyXG4gICAgaWYgKCF0aGlzLl9tYXNrVmFsdWUpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgdGhpcy5fbWFza1NlcnZpY2UubWFza0V4cHJlc3Npb24gPSB0aGlzLl9yZXBlYXRQYXR0ZXJuU3ltYm9scyh0aGlzLl9tYXNrVmFsdWUpO1xyXG4gICAgdGhpcy5fbWFza1NlcnZpY2UuZm9ybUVsZW1lbnRQcm9wZXJ0eSA9IFtcclxuICAgICAgJ3ZhbHVlJyxcclxuICAgICAgdGhpcy5fbWFza1NlcnZpY2UuYXBwbHlNYXNrKFxyXG4gICAgICAgIHRoaXMuX2lucHV0VmFsdWUsXHJcbiAgICAgICAgdGhpcy5fbWFza1NlcnZpY2UubWFza0V4cHJlc3Npb25cclxuICAgICAgKVxyXG4gICAgXTtcclxuICB9XHJcblxyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIHNldCBzcGVjaWFsQ2hhcmFjdGVycyh2YWx1ZTogSUNvbmZpZ1snc3BlY2lhbENoYXJhY3RlcnMnXSkge1xyXG4gICAgaWYgKFxyXG4gICAgICAhdmFsdWUgfHxcclxuICAgICAgIUFycmF5LmlzQXJyYXkodmFsdWUpIHx8XHJcbiAgICAgIChBcnJheS5pc0FycmF5KHZhbHVlKSAmJiAhdmFsdWUubGVuZ3RoKVxyXG4gICAgKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuICAgIHRoaXMuX21hc2tTZXJ2aWNlLm1hc2tTcGVjaWFsQ2hhcmFjdGVycyA9IHZhbHVlO1xyXG4gIH1cclxuXHJcbiAgQElucHV0KClcclxuICBwdWJsaWMgc2V0IHBhdHRlcm5zKHZhbHVlOiBJQ29uZmlnWydw