ng-swipe-to-delete
Version:
Material Swipe to delete list for Angular Projects.
501 lines (485 loc) • 66.4 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('@angular/material'), require('@angular/animations'), require('@angular/platform-browser'), require('@angular/common')) :
typeof define === 'function' && define.amd ? define('ng-swipe-to-delete', ['exports', '@angular/core', '@angular/material', '@angular/animations', '@angular/platform-browser', '@angular/common'], factory) :
(factory((global['ng-swipe-to-delete'] = {}),global.ng.core,global.ng.material,global.ng.animations,global.ng.platformBrowser,global.ng.common));
}(this, (function (exports,core,material,animations,platformBrowser,common) { 'use strict';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
var MaterialsModule = (function () {
function MaterialsModule() {
}
MaterialsModule.decorators = [
{ type: core.NgModule, args: [{
imports: [
material.MatIconModule,
material.MatListModule,
material.MatRippleModule,
],
declarations: [],
exports: [
material.MatIconModule,
material.MatListModule,
material.MatRippleModule,
]
},] },
];
return MaterialsModule;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/** @enum {string} */
var ListType = {
SINGLELINE: 'singleline',
MULTILINE: 'multiline',
LISTWITHICON: 'listwithicon',
LISTWITHIMAGE: 'listwithimage',
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/** @enum {string} */
var Warnings = {
CONFIG_NOT_LOADED: 'CONFIG_NOT_LOADED',
ADDING_DEFAULT_SLIDE_THRESHOLD: 'ADDING_DEFAULT_SLIDE_THRESHOLD',
ZERO_SLIDE_THRESHOLD_NOT_ALLOWED: 'ZERO_SLIDE_THRESHOLD_NOT_ALLOWED',
SLIDE_THRESHOLD_NOT_FOUND: 'SLIDE_THRESHOLD_NOT_FOUND',
MAX_SLIDE_THRESHOLD_NOT_ALLOWED: 'MAX_SLIDE_THRESHOLD_NOT_ALLOWED',
INVALID_SLIDE_THRESHOLD_NOT_ALLOWED: 'INVALID_SLIDE_THRESHOLD_NOT_ALLOWED',
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
var /** @type {?} */ Constants = {
CONFIG_NOT_LOADED: "You have not provided the configuration values, default will be loaded.",
ADDING_DEFAULT_SLIDE_THRESHOLD: "Will keep it default i.e.",
SLIDE_THRESHOLD_NOT_FOUND: "You have not provided the slideThreshold.",
ZERO_SLIDE_THRESHOLD_NOT_ALLOWED: "slideThreshold value can not be 0 or less than 0.",
MAX_SLIDE_THRESHOLD_NOT_ALLOWED: "slideThreshold value should be less than 50.",
INVALID_SLIDE_THRESHOLD_NOT_ALLOWED: "slideThreshold value is invalid, Expecting number between 0 to 50.",
MAX_SLIDE_THRESHOLD: 50,
MIN_SLIDE_THRESHOLD: 0,
DEFAULT_SLIDE_THRESHOLD: 12,
NUMBER_OF_DELETE_ICONS: 2,
DEFAULT_CLASS_NAME: "ngstd-main-canvas"
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
var NgSwipeToDeleteComponent = (function () {
function NgSwipeToDeleteComponent() {
this.configuration = null;
this.deletedItem = new core.EventEmitter();
this.ngstdIndexNumber = null;
this.disableWarnings = false;
this.listType = null;
this.numberOfDeleteIcon = null;
this.classname = null;
this.isInvalidConfig = null;
this.elementLeftSign = true;
}
/**
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.ngOnInit = /**
* @return {?}
*/
function () {
this.initializeSWipeList();
};
/**
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.initializeSWipeList = /**
* @return {?}
*/
function () {
this.detectInvalidConfig();
this.setDisableWarnings();
this.setslideThreshold();
this.setNumberOfDeleteIcon();
this.setlistType();
};
/**
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.detectInvalidConfig = /**
* @return {?}
*/
function () {
if (this.configuration === null || this.configuration === undefined || this.configuration === '') {
this.isInvalidConfig = true;
this.logWarnings(Warnings.CONFIG_NOT_LOADED);
}
else {
this.isInvalidConfig = false;
}
};
/**
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.setNumberOfDeleteIcon = /**
* @return {?}
*/
function () {
var /** @type {?} */ config = this.configuration;
if (this.isInvalidConfig || config.numberOfDeleteIcon === 2) {
this.numberOfDeleteIcon = Constants.NUMBER_OF_DELETE_ICONS;
}
else {
this.numberOfDeleteIcon = null;
}
};
/**
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.setslideThreshold = /**
* @return {?}
*/
function () {
if (this.isInvalidConfig) {
this.slideThreshold = Constants.DEFAULT_SLIDE_THRESHOLD;
this.logWarnings(Warnings.SLIDE_THRESHOLD_NOT_FOUND, Constants.ADDING_DEFAULT_SLIDE_THRESHOLD + " " + Constants.DEFAULT_SLIDE_THRESHOLD + "%.");
return;
}
var /** @type {?} */ config = this.configuration;
if (config.slideThreshold === null || config.slideThreshold === undefined || typeof config.slideThreshold !== 'number') {
if (typeof config.slideThreshold !== 'number') {
this.logWarnings(Warnings.INVALID_SLIDE_THRESHOLD_NOT_ALLOWED, Constants.ADDING_DEFAULT_SLIDE_THRESHOLD + " " + Constants.DEFAULT_SLIDE_THRESHOLD + "%.");
}
else {
this.logWarnings(Warnings.SLIDE_THRESHOLD_NOT_FOUND, Constants.ADDING_DEFAULT_SLIDE_THRESHOLD + " " + Constants.DEFAULT_SLIDE_THRESHOLD + "%.");
}
this.slideThreshold = Constants.DEFAULT_SLIDE_THRESHOLD;
}
else {
if (config.slideThreshold < Constants.MIN_SLIDE_THRESHOLD || config.slideThreshold === Constants.MIN_SLIDE_THRESHOLD || config.slideThreshold > Constants.MAX_SLIDE_THRESHOLD) {
if (config.slideThreshold > Constants.MAX_SLIDE_THRESHOLD) {
this.logWarnings(Warnings.MAX_SLIDE_THRESHOLD_NOT_ALLOWED, Constants.ADDING_DEFAULT_SLIDE_THRESHOLD + " " + Constants.DEFAULT_SLIDE_THRESHOLD + "%.");
}
if (config.slideThreshold < Constants.MIN_SLIDE_THRESHOLD || config.slideThreshold === Constants.MIN_SLIDE_THRESHOLD) {
this.logWarnings(Warnings.ZERO_SLIDE_THRESHOLD_NOT_ALLOWED, Constants.ADDING_DEFAULT_SLIDE_THRESHOLD + " " + Constants.DEFAULT_SLIDE_THRESHOLD + "%.");
}
this.slideThreshold = Constants.DEFAULT_SLIDE_THRESHOLD;
}
else {
this.slideThreshold = config.slideThreshold;
}
}
};
/**
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.setlistType = /**
* @return {?}
*/
function () {
var /** @type {?} */ config = this.configuration;
if (this.isInvalidConfig || config.listType === "" || config.listType === undefined || config.listType === null) {
this.listType = ListType.SINGLELINE;
}
else {
var /** @type {?} */ listType = config.listType.trim();
switch (listType) {
case ListType.SINGLELINE:
case ListType.MULTILINE:
case ListType.LISTWITHICON:
case ListType.LISTWITHIMAGE:
this.listType = listType;
break;
default:
this.listType = ListType.SINGLELINE;
}
}
};
/**
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.setDisableWarnings = /**
* @return {?}
*/
function () {
if (this.isInvalidConfig) {
this.disableWarnings = false;
}
else {
var /** @type {?} */ config = this.configuration;
this.disableWarnings = (config.disableWarnings && config.disableWarnings !== undefined && config.disableWarnings !== null) ? true : false;
}
};
/**
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.getClassName = /**
* @return {?}
*/
function () {
if (this.isInvalidConfig) {
return "" + Constants.DEFAULT_CLASS_NAME;
}
else {
if (this.configuration.classname !== '' && this.configuration.classname !== null && this.configuration.classname !== undefined) {
return Constants.DEFAULT_CLASS_NAME + " " + this.configuration.classname;
}
else {
return "" + Constants.DEFAULT_CLASS_NAME;
}
}
};
/**
* @param {?} action
* @param {?} index
* @param {?} elementRefrence
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.panend = /**
* @param {?} action
* @param {?} index
* @param {?} elementRefrence
* @return {?}
*/
function (action, index, elementRefrence) {
var /** @type {?} */ currentMargin = this.getLeftPosition(elementRefrence);
if (currentMargin > this.slideThreshold ||
(currentMargin < -this.slideThreshold && this.numberOfDeleteIcon === Constants.NUMBER_OF_DELETE_ICONS)) {
this.removeElement(index);
}
else {
this.ngstdIndexNumber = index;
}
};
/**
* @param {?} action
* @param {?} elementRefrence
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.panmove = /**
* @param {?} action
* @param {?} elementRefrence
* @return {?}
*/
function (action, elementRefrence) {
elementRefrence.style.left = action.deltaX + 'px';
elementRefrence.offsetLeft > 0 ? this.elementLeftSign = true : this.elementLeftSign = false;
};
/**
* @param {?} event
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.alignComplete = /**
* @param {?} event
* @return {?}
*/
function (event) {
event.element.style.left = '0px';
event.element.offsetLeft > 0 ? this.elementLeftSign = true : this.elementLeftSign = false;
this.ngstdIndexNumber = null;
};
/**
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.getLeftSign = /**
* @return {?}
*/
function () {
return this.elementLeftSign ? true : false;
};
/**
* @param {?} index
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.removeElement = /**
* @param {?} index
* @return {?}
*/
function (index) {
var /** @type {?} */ deletedItem = this.items[index];
this.items.splice(index, 1);
this.deletedItem.emit(deletedItem);
};
/**
* @param {?} elementRefrence
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.getLeftPosition = /**
* @param {?} elementRefrence
* @return {?}
*/
function (elementRefrence) {
var /** @type {?} */ currentleftPosition = elementRefrence.style.left.slice(0, -2);
if (currentleftPosition !== null) {
return (parseInt(currentleftPosition, 10) * 100) / window.innerWidth;
}
else {
return 0;
}
};
/**
* @param {?} warningFor
* @param {?=} extraMessage
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.logWarnings = /**
* @param {?} warningFor
* @param {?=} extraMessage
* @return {?}
*/
function (warningFor, extraMessage) {
if (extraMessage === void 0) {
extraMessage = null;
}
if (this.disableWarnings) {
return;
}
switch (warningFor) {
case Warnings.CONFIG_NOT_LOADED:
case Warnings.SLIDE_THRESHOLD_NOT_FOUND:
case Warnings.ZERO_SLIDE_THRESHOLD_NOT_ALLOWED:
case Warnings.MAX_SLIDE_THRESHOLD_NOT_ALLOWED:
case Warnings.INVALID_SLIDE_THRESHOLD_NOT_ALLOWED:
extraMessage === null ? console.warn(this.getConstValue(warningFor)) : console.warn(this.getConstValue(warningFor), extraMessage);
break;
default:
}
};
/**
* @param {?} constantName
* @return {?}
*/
NgSwipeToDeleteComponent.prototype.getConstValue = /**
* @param {?} constantName
* @return {?}
*/
function (constantName) {
return Constants[constantName];
};
NgSwipeToDeleteComponent.decorators = [
{ type: core.Component, args: [{
selector: 'ng-swipe-to-delete',
template: "<div [ngClass]=\"getClassName()\">\n <mat-list [@listAnimation]=\"items.length\">\n <mat-list-item class=\"ngstd-list-item\" *ngFor=\"let item of items;let i = index\">\n \n <div class=\"ngstd-delete-indicator\">\n <i class=\"material-icons ngstd-delete-icon\" *ngIf=\"getLeftSign()\">delete_sweep</i>\n <span> </span>\n <i class=\"material-icons ngstd-delete-icon\" *ngIf=\"numberOfDeleteIcon === 2 && !getLeftSign()\">delete_sweep</i>\n </div>\n\n <div #elementRefrence class=\"ngstd-item-container \"\n (panend)=\"panend($event, i, elementRefrence)\" \n (panmove)=\"panmove($event,elementRefrence)\" \n [@slideLeft]=\"ngstdIndexNumber === i\"\n (@slideLeft.done)=alignComplete($event)\n >\n <ng-container *ngIf=\"listType === 'listwithimage'\">\n <img matListAvatar src=\"{{item.img}}\" alt=\"{{item.title}}\">\n <div class=\"mat-list-text ngstd-details\">\n <h3 matLine> {{item.title}}</h3>\n <p matLine>\n <span> {{item.description}} </span>\n </p>\n </div>\n </ng-container>\n <ng-container *ngIf=\"listType === 'listwithicon'\">\n <mat-icon class=\"ngstd-icon\" mat-list-icon>{{item.icon}}</mat-icon>\n <div class=\"mat-list-text ngstd-details\">\n <h4 mat-line>{{item.title}}</h4>\n <p mat-line> {{item.description}} </p>\n </div>\n </ng-container>\n <ng-container *ngIf=\"listType === 'singleline'\">\n <mat-list-item> {{item.title}} </mat-list-item>\n </ng-container>\n <ng-container *ngIf=\"listType === 'multiline'\">\n <div class=\"mat-list-text ngstd-details\">\n <h3 matLine> {{item.title}} </h3>\n <p matLine>\n <span> {{item.description}} </span>\n <span class=\"demo-2\"> -- {{item.description}} </span>\n </p>\n </div>\n </ng-container>\n </div>\n <mat-divider></mat-divider>\n </mat-list-item>\n </mat-list>\n</div>\n\n",
styles: [".ngstd-main-canvas /deep/ mat-list-item .mat-list-item-content{padding:0!important}.ngstd-main-canvas .ngstd-delete-indicator{height:97%;width:98%;background-color:red;display:flex;justify-content:space-between;position:absolute;align-items:center;flex-shrink:0;margin-left:.5%}.ngstd-main-canvas .ngstd-delete-indicator .ngstd-delete-icon{margin-left:16px;margin-right:16px;width:24px;height:24px;font-size:24px;color:#fff}.ngstd-main-canvas .ngstd-item-container{padding:0 16px!important;background-color:#fff;width:100%;display:flex;flex-direction:row;align-items:center;box-sizing:border-box;position:relative;height:inherit}.ngstd-main-canvas .ngstd-item-container .ngstd-details{padding-left:16px!important}.ngstd-main-canvas .ngstd-item-container .ngstd-icon{color:rgba(0,0,0,.54)}"],
animations: [
animations.trigger('listAnimation', [
animations.transition('* => *', [
animations.query(':leave', [
animations.stagger(100, [
animations.animate('0s', animations.style({ opacity: '0' })),
animations.animate('0.2s', animations.style({ height: '0px', opacity: '0', display: 'none' }))
])
], { optional: true })
])
]),
animations.trigger('slideLeft', [
animations.transition('* => *', animations.animate(100, animations.keyframes([
animations.style({ left: '*', offset: 0 }),
animations.style({ left: '0', offset: 1 }),
])))
])
]
},] },
];
/** @nocollapse */
NgSwipeToDeleteComponent.ctorParameters = function () { return []; };
NgSwipeToDeleteComponent.propDecorators = {
"items": [{ type: core.Input },],
"configuration": [{ type: core.Input },],
"deletedItem": [{ type: core.Output },],
};
return NgSwipeToDeleteComponent;
}());
/*! *****************************************************************************
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.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b)
if (b.hasOwnProperty(p))
d[p] = b[p]; };
function __extends(d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
var GestureConfig = (function (_super) {
__extends(GestureConfig, _super);
function GestureConfig() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.overrides = {
pan: {
touchAction: 'auto',
direction: 6
},
pinch: {
enable: false
},
rotate: {
enable: false
},
swipe: {
enable: false
}
};
return _this;
}
return GestureConfig;
}(platformBrowser.HammerGestureConfig));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
var NgSwipeToDeleteModule = (function () {
function NgSwipeToDeleteModule() {
}
NgSwipeToDeleteModule.decorators = [
{ type: core.NgModule, args: [{
imports: [
common.CommonModule,
MaterialsModule
],
declarations: [NgSwipeToDeleteComponent],
exports: [
NgSwipeToDeleteComponent
],
providers: [{
provide: platformBrowser.HAMMER_GESTURE_CONFIG,
useClass: GestureConfig,
}]
},] },
];
return NgSwipeToDeleteModule;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
exports.NgSwipeToDeleteModule = NgSwipeToDeleteModule;
exports.ɵc = GestureConfig;
exports.ɵa = MaterialsModule;
exports.ɵb = NgSwipeToDeleteComponent;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctc3dpcGUtdG8tZGVsZXRlLnVtZC5qcy5tYXAiLCJzb3VyY2VzIjpbIm5nOi8vbmctc3dpcGUtdG8tZGVsZXRlL3NyYy9hcHAvbW9kdWxlL25nLXN3aXBlLXRvLWRlbGV0ZS9tYXRlcmlhbHMubW9kdWxlLnRzIiwibmc6Ly9uZy1zd2lwZS10by1kZWxldGUvc3JjL2FwcC9tb2R1bGUvbmctc3dpcGUtdG8tZGVsZXRlL2VudW1zL2xpc3QtdHlwZS50cyIsIm5nOi8vbmctc3dpcGUtdG8tZGVsZXRlL3NyYy9hcHAvbW9kdWxlL25nLXN3aXBlLXRvLWRlbGV0ZS9lbnVtcy93YXJuaW5ncy50cyIsIm5nOi8vbmctc3dpcGUtdG8tZGVsZXRlL3NyYy9hcHAvbW9kdWxlL25nLXN3aXBlLXRvLWRlbGV0ZS9jb25zdGFudHMvY29uc3RhbnRzLnRzIiwibmc6Ly9uZy1zd2lwZS10by1kZWxldGUvc3JjL2FwcC9tb2R1bGUvbmctc3dpcGUtdG8tZGVsZXRlL25nLXN3aXBlLXRvLWRlbGV0ZS5jb21wb25lbnQudHMiLG51bGwsIm5nOi8vbmctc3dpcGUtdG8tZGVsZXRlL3NyYy9hcHAvbW9kdWxlL25nLXN3aXBlLXRvLWRlbGV0ZS9jb25maWcvZ2VzdHVyZS1jb25maWcudHMiLCJuZzovL25nLXN3aXBlLXRvLWRlbGV0ZS9zcmMvYXBwL21vZHVsZS9uZy1zd2lwZS10by1kZWxldGUvbmctc3dpcGUtdG8tZGVsZXRlLm1vZHVsZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBOZ01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcblxuaW1wb3J0IHtcbiAgTWF0SWNvbk1vZHVsZSxcbiAgTWF0TGlzdE1vZHVsZSxcbiAgTWF0UmlwcGxlTW9kdWxlLFxufSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbCc7XG5cbkBOZ01vZHVsZSh7XG4gIGltcG9ydHM6IFtcbiAgICBNYXRJY29uTW9kdWxlLFxuICAgIE1hdExpc3RNb2R1bGUsXG4gICAgTWF0UmlwcGxlTW9kdWxlLFxuICBdLFxuICBkZWNsYXJhdGlvbnM6IFtdLFxuICBleHBvcnRzOiBbXG4gICAgTWF0SWNvbk1vZHVsZSxcbiAgICBNYXRMaXN0TW9kdWxlLFxuICAgIE1hdFJpcHBsZU1vZHVsZSxcbiAgXVxufSlcbmV4cG9ydCBjbGFzcyBNYXRlcmlhbHNNb2R1bGUgeyB9XG4iLCJleHBvcnQgZW51bSBMaXN0VHlwZSB7XHJcbiAgICBTSU5HTEVMSU5FID0gJ3NpbmdsZWxpbmUnLFxyXG4gICAgTVVMVElMSU5FID0gJ211bHRpbGluZScsXHJcbiAgICBMSVNUV0lUSElDT04gPSAnbGlzdHdpdGhpY29uJyxcclxuICAgIExJU1RXSVRISU1BR0UgPSAnbGlzdHdpdGhpbWFnZScsXHJcbn1cclxuIiwiZXhwb3J0IGVudW0gV2FybmluZ3Mge1xyXG4gICAgQ09ORklHX05PVF9MT0FERUQgPSAnQ09ORklHX05PVF9MT0FERUQnLFxyXG4gICAgQURESU5HX0RFRkFVTFRfU0xJREVfVEhSRVNIT0xEID0gJ0FERElOR19ERUZBVUxUX1NMSURFX1RIUkVTSE9MRCcsXHJcbiAgICBaRVJPX1NMSURFX1RIUkVTSE9MRF9OT1RfQUxMT1dFRCA9ICdaRVJPX1NMSURFX1RIUkVTSE9MRF9OT1RfQUxMT1dFRCcsXHJcbiAgICBTTElERV9USFJFU0hPTERfTk9UX0ZPVU5EID0gJ1NMSURFX1RIUkVTSE9MRF9OT1RfRk9VTkQnLFxyXG4gICAgTUFYX1NMSURFX1RIUkVTSE9MRF9OT1RfQUxMT1dFRCA9ICdNQVhfU0xJREVfVEhSRVNIT0xEX05PVF9BTExPV0VEJyxcclxuICAgIElOVkFMSURfU0xJREVfVEhSRVNIT0xEX05PVF9BTExPV0VEID0gJ0lOVkFMSURfU0xJREVfVEhSRVNIT0xEX05PVF9BTExPV0VEJ1xyXG59XHJcbiIsImV4cG9ydCBjb25zdCBDb25zdGFudHMgPSB7XHJcbiAgICBDT05GSUdfTk9UX0xPQURFRCA6IGBZb3UgaGF2ZSBub3QgcHJvdmlkZWQgdGhlIGNvbmZpZ3VyYXRpb24gdmFsdWVzLCBkZWZhdWx0IHdpbGwgYmUgbG9hZGVkLmAsXHJcbiAgICBBRERJTkdfREVGQVVMVF9TTElERV9USFJFU0hPTEQ6IGBXaWxsIGtlZXAgaXQgZGVmYXVsdCBpLmUuYCxcclxuICAgIFNMSURFX1RIUkVTSE9MRF9OT1RfRk9VTkQ6IGBZb3UgaGF2ZSBub3QgcHJvdmlkZWQgdGhlIHNsaWRlVGhyZXNob2xkLmAsXHJcbiAgICBaRVJPX1NMSURFX1RIUkVTSE9MRF9OT1RfQUxMT1dFRDogYHNsaWRlVGhyZXNob2xkIHZhbHVlIGNhbiBub3QgYmUgMCBvciBsZXNzIHRoYW4gMC5gLFxyXG4gICAgTUFYX1NMSURFX1RIUkVTSE9MRF9OT1RfQUxMT1dFRDogYHNsaWRlVGhyZXNob2xkIHZhbHVlIHNob3VsZCBiZSBsZXNzIHRoYW4gNTAuYCxcclxuICAgIElOVkFMSURfU0xJREVfVEhSRVNIT0xEX05PVF9BTExPV0VEOiBgc2xpZGVUaHJlc2hvbGQgdmFsdWUgaXMgaW52YWxpZCwgRXhwZWN0aW5nIG51bWJlciBiZXR3ZWVuIDAgdG8gNTAuYCxcclxuICAgIE1BWF9TTElERV9USFJFU0hPTEQ6IDUwLFxyXG4gICAgTUlOX1NMSURFX1RIUkVTSE9MRDogMCxcclxuICAgIERFRkFVTFRfU0xJREVfVEhSRVNIT0xEOiAxMixcclxuICAgIE5VTUJFUl9PRl9ERUxFVEVfSUNPTlMgOiAyLFxyXG4gICAgREVGQVVMVF9DTEFTU19OQU1FOiBgbmdzdGQtbWFpbi1jYW52YXNgXHJcbn07XHJcbiIsImltcG9ydCB7IENvbXBvbmVudCwgT25Jbml0LCBJbnB1dCwgT3V0cHV0LCBFdmVudEVtaXR0ZXIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgdHJpZ2dlciwgc3R5bGUsIGtleWZyYW1lcywgdHJhbnNpdGlvbiwgYW5pbWF0ZSwgcXVlcnksIHN0YWdnZXIgfSBmcm9tICdAYW5ndWxhci9hbmltYXRpb25zJztcclxuXHJcbmltcG9ydCB7IENvbmZpZ3VyYXRpb24gfSBmcm9tICcuL2ludGVyZmFjZXMvY29uZmlndXJhdGlvbic7XHJcbmltcG9ydCB7IExpc3RUeXBlIH0gZnJvbSAnLi9lbnVtcy9saXN0LXR5cGUnO1xyXG5pbXBvcnQgeyBXYXJuaW5ncyB9IGZyb20gJy4vZW51bXMvd2FybmluZ3MnO1xyXG5pbXBvcnQgeyBDb25zdGFudHMgfSBmcm9tICcuL2NvbnN0YW50cy9jb25zdGFudHMnO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICduZy1zd2lwZS10by1kZWxldGUnLFxyXG4gIHRlbXBsYXRlOiBgPGRpdiBbbmdDbGFzc109XCJnZXRDbGFzc05hbWUoKVwiPlxyXG4gIDxtYXQtbGlzdCBbQGxpc3RBbmltYXRpb25dPVwiaXRlbXMubGVuZ3RoXCI+XHJcbiAgICA8bWF0LWxpc3QtaXRlbSBjbGFzcz1cIm5nc3RkLWxpc3QtaXRlbVwiICpuZ0Zvcj1cImxldCBpdGVtIG9mIGl0ZW1zO2xldCBpID0gaW5kZXhcIj5cclxuICAgICAgXHJcbiAgICAgIDxkaXYgY2xhc3M9XCJuZ3N0ZC1kZWxldGUtaW5kaWNhdG9yXCI+XHJcbiAgICAgICAgPGkgY2xhc3M9XCJtYXRlcmlhbC1pY29ucyBuZ3N0ZC1kZWxldGUtaWNvblwiICpuZ0lmPVwiZ2V0TGVmdFNpZ24oKVwiPmRlbGV0ZV9zd2VlcDwvaT5cclxuICAgICAgICA8c3Bhbj4mbmJzcDs8L3NwYW4+XHJcbiAgICAgICAgPGkgY2xhc3M9XCJtYXRlcmlhbC1pY29ucyBuZ3N0ZC1kZWxldGUtaWNvblwiICpuZ0lmPVwibnVtYmVyT2ZEZWxldGVJY29uID09PSAyICYmICFnZXRMZWZ0U2lnbigpXCI+ZGVsZXRlX3N3ZWVwPC9pPlxyXG4gICAgICA8L2Rpdj5cclxuXHJcbiAgICAgIDxkaXYgI2VsZW1lbnRSZWZyZW5jZSBjbGFzcz1cIm5nc3RkLWl0ZW0tY29udGFpbmVyIFwiXHJcbiAgICAgICAgKHBhbmVuZCk9XCJwYW5lbmQoJGV2ZW50LCBpLCBlbGVtZW50UmVmcmVuY2UpXCIgXHJcbiAgICAgICAgKHBhbm1vdmUpPVwicGFubW92ZSgkZXZlbnQsZWxlbWVudFJlZnJlbmNlKVwiIFxyXG4gICAgICAgIFtAc2xpZGVMZWZ0XT1cIm5nc3RkSW5kZXhOdW1iZXIgPT09IGlcIlxyXG4gICAgICAgIChAc2xpZGVMZWZ0LmRvbmUpPWFsaWduQ29tcGxldGUoJGV2ZW50KVxyXG4gICAgICA+XHJcbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImxpc3RUeXBlID09PSAnbGlzdHdpdGhpbWFnZSdcIj5cclxuICAgICAgICAgIDxpbWcgbWF0TGlzdEF2YXRhciBzcmM9XCJ7e2l0ZW0uaW1nfX1cIiBhbHQ9XCJ7e2l0ZW0udGl0bGV9fVwiPlxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cIm1hdC1saXN0LXRleHQgbmdzdGQtZGV0YWlsc1wiPlxyXG4gICAgICAgICAgICA8aDMgbWF0TGluZT4ge3tpdGVtLnRpdGxlfX08L2gzPlxyXG4gICAgICAgICAgICA8cCBtYXRMaW5lPlxyXG4gICAgICAgICAgICAgIDxzcGFuPiB7e2l0ZW0uZGVzY3JpcHRpb259fSA8L3NwYW4+XHJcbiAgICAgICAgICAgIDwvcD5cclxuICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDwvbmctY29udGFpbmVyPlxyXG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJsaXN0VHlwZSA9PT0gJ2xpc3R3aXRoaWNvbidcIj5cclxuICAgICAgICAgIDxtYXQtaWNvbiBjbGFzcz1cIm5nc3RkLWljb25cIiBtYXQtbGlzdC1pY29uPnt7aXRlbS5pY29ufX08L21hdC1pY29uPlxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cIm1hdC1saXN0LXRleHQgbmdzdGQtZGV0YWlsc1wiPlxyXG4gICAgICAgICAgICA8aDQgbWF0LWxpbmU+e3tpdGVtLnRpdGxlfX08L2g0PlxyXG4gICAgICAgICAgICA8cCBtYXQtbGluZT4ge3tpdGVtLmRlc2NyaXB0aW9ufX0gPC9wPlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgPC9uZy1jb250YWluZXI+XHJcbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImxpc3RUeXBlID09PSAnc2luZ2xlbGluZSdcIj5cclxuICAgICAgICAgIDxtYXQtbGlzdC1pdGVtPiB7e2l0ZW0udGl0bGV9fSA8L21hdC1saXN0LWl0ZW0+XHJcbiAgICAgICAgPC9uZy1jb250YWluZXI+XHJcbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImxpc3RUeXBlID09PSAnbXVsdGlsaW5lJ1wiPlxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cIm1hdC1saXN0LXRleHQgbmdzdGQtZGV0YWlsc1wiPlxyXG4gICAgICAgICAgICA8aDMgbWF0TGluZT4ge3tpdGVtLnRpdGxlfX0gPC9oMz5cclxuICAgICAgICAgICAgPHAgbWF0TGluZT5cclxuICAgICAgICAgICAgICA8c3Bhbj4ge3tpdGVtLmRlc2NyaXB0aW9ufX0gPC9zcGFuPlxyXG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZGVtby0yXCI+IC0tIHt7aXRlbS5kZXNjcmlwdGlvbn19IDwvc3Bhbj5cclxuICAgICAgICAgICAgPC9wPlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgPC9uZy1jb250YWluZXI+XHJcbiAgICAgIDwvZGl2PlxyXG4gICAgICA8bWF0LWRpdmlkZXI+PC9tYXQtZGl2aWRlcj5cclxuICAgIDwvbWF0LWxpc3QtaXRlbT5cclxuICA8L21hdC1saXN0PlxyXG48L2Rpdj5cclxuXHJcbmAsXHJcbiAgc3R5bGVzOiBbYC5uZ3N0ZC1tYWluLWNhbnZhcyAvZGVlcC8gbWF0LWxpc3QtaXRlbSAubWF0LWxpc3QtaXRlbS1jb250ZW50e3BhZGRpbmc6MCFpbXBvcnRhbnR9Lm5nc3RkLW1haW4tY2FudmFzIC5uZ3N0ZC1kZWxldGUtaW5kaWNhdG9ye2hlaWdodDo5NyU7d2lkdGg6OTglO2JhY2tncm91bmQtY29sb3I6cmVkO2Rpc3BsYXk6ZmxleDtqdXN0aWZ5LWNvbnRlbnQ6c3BhY2UtYmV0d2Vlbjtwb3NpdGlvbjphYnNvbHV0ZTthbGlnbi1pdGVtczpjZW50ZXI7ZmxleC1zaHJpbms6MDttYXJnaW4tbGVmdDouNSV9Lm5nc3RkLW1haW4tY2FudmFzIC5uZ3N0ZC1kZWxldGUtaW5kaWNhdG9yIC5uZ3N0ZC1kZWxldGUtaWNvbnttYXJnaW4tbGVmdDoxNnB4O21hcmdpbi1yaWdodDoxNnB4O3dpZHRoOjI0cHg7aGVpZ2h0OjI0cHg7Zm9udC1zaXplOjI0cHg7Y29sb3I6I2ZmZn0ubmdzdGQtbWFpbi1jYW52YXMgLm5nc3RkLWl0ZW0tY29udGFpbmVye3BhZGRpbmc6MCAxNnB4IWltcG9ydGFudDtiYWNrZ3JvdW5kLWNvbG9yOiNmZmY7d2lkdGg6MTAwJTtkaXNwbGF5OmZsZXg7ZmxleC1kaXJlY3Rpb246cm93O2FsaWduLWl0ZW1zOmNlbnRlcjtib3gtc2l6aW5nOmJvcmRlci1ib3g7cG9zaXRpb246cmVsYXRpdmU7aGVpZ2h0OmluaGVyaXR9Lm5nc3RkLW1haW4tY2FudmFzIC5uZ3N0ZC1pdGVtLWNvbnRhaW5lciAubmdzdGQtZGV0YWlsc3twYWRkaW5nLWxlZnQ6MTZweCFpbXBvcnRhbnR9Lm5nc3RkLW1haW4tY2FudmFzIC5uZ3N0ZC1pdGVtLWNvbnRhaW5lciAubmdzdGQtaWNvbntjb2xvcjpyZ2JhKDAsMCwwLC41NCl9YF0sXHJcbiAgYW5pbWF0aW9uczogW1xyXG4gICAgdHJpZ2dlcignbGlzdEFuaW1hdGlvbicsIFtcclxuICAgICAgdHJhbnNpdGlvbignKiA9PiAqJywgW1xyXG4gICAgICAgIHF1ZXJ5KCc6bGVhdmUnLCBbXHJcbiAgICAgICAgICBzdGFnZ2VyKDEwMCwgW1xyXG4gICAgICAgICAgICBhbmltYXRlKCcwcycsIHN0eWxlKHsgb3BhY2l0eTogJzAnIH0pKSxcclxuICAgICAgICAgICAgYW5pbWF0ZSgnMC4ycycsIHN0eWxlKHsgaGVpZ2h0OiAnMHB4Jywgb3BhY2l0eTogJzAnLCBkaXNwbGF5OiAnbm9uZScgfSkpXHJcbiAgICAgICAgICBdKVxyXG4gICAgICAgIF0sIHsgb3B0aW9uYWw6IHRydWUgfSlcclxuICAgICAgXSlcclxuICAgIF0pLFxyXG4gICAgdHJpZ2dlcignc2xpZGVMZWZ0JywgW1xyXG4gICAgICB0cmFuc2l0aW9uKCcqID0+IConLCBhbmltYXRlKDEwMCwga2V5ZnJhbWVzKFtcclxuICAgICAgICBzdHlsZSh7IGxlZnQ6ICcqJywgb2Zmc2V0OiAwIH0pLFxyXG4gICAgICAgIHN0eWxlKHsgbGVmdDogJzAnLCBvZmZzZXQ6IDEgfSksXHJcbiAgICAgIF0pXHJcbiAgICAgICkpXHJcbiAgICBdKVxyXG4gIF1cclxufSlcclxuXHJcbmV4cG9ydCBjbGFzcyBOZ1N3aXBlVG9EZWxldGVDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xyXG4gIEBJbnB1dCgpIGl0ZW1zOiBhbnk7XHJcbiAgQElucHV0KCkgY29uZmlndXJhdGlvbjogQ29uZmlndXJhdGlvbiA9IG51bGw7XHJcbiAgQE91dHB1dCgpIGRlbGV0ZWRJdGVtID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XHJcbiAgbmdzdGRJbmRleE51bWJlcjpudW1iZXIgPSBudWxsO1xyXG4gIGRpc2FibGVXYXJuaW5ncyA9IGZhbHNlO1xyXG4gIGxpc3RUeXBlOiBzdHJpbmcgPSBudWxsO1xyXG4gIHNsaWRlVGhyZXNob2xkOiBudW1iZXI7XHJcbiAgbnVtYmVyT2ZEZWxldGVJY29uOiBudW1iZXIgPSBudWxsO1xyXG4gIGNsYXNzbmFtZTogc3RyaW5nID0gIG51bGw7XHJcbiAgaXNJbnZhbGlkQ29uZmlnOiBib29sZWFuID0gIG51bGw7XHJcbiAgZWxlbWVudExlZnRTaWduID0gdHJ1ZTtcclxuICBjb25zdHJ1Y3RvcigpIHsgfVxyXG4gIG5nT25Jbml0KCkge1xyXG4gICAgdGhpcy5pbml0aWFsaXplU1dpcGVMaXN0KCk7XHJcbiAgfVxyXG4gIGluaXRpYWxpemVTV2lwZUxpc3QoKTogdm9pZCB7XHJcbiAgICB0aGlzLmRldGVjdEludmFsaWRDb25maWcoKTtcclxuICAgIHRoaXMuc2V0RGlzYWJsZVdhcm5pbmdzKCk7XHJcbiAgICB0aGlzLnNldHNsaWRlVGhyZXNob2xkKCk7XHJcbiAgICB0aGlzLnNldE51bWJlck9mRGVsZXRlSWNvbigpO1xyXG4gICAgdGhpcy5zZXRsaXN0VHlwZSgpO1xyXG4gIH1cclxuICBkZXRlY3RJbnZhbGlkQ29uZmlnKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuY29uZmlndXJhdGlvbiA9PT0gbnVsbCB8fCB0aGlzLmNvbmZpZ3VyYXRpb24gPT09IHVuZGVmaW5lZCB8fCB0aGlzLmNvbmZpZ3VyYXRpb24gPT09ICcnKSB7XHJcbiAgICAgIHRoaXMuaXNJbnZhbGlkQ29uZmlnID0gdHJ1ZTtcclxuICAgICAgdGhpcy5sb2dXYXJuaW5ncyhXYXJuaW5ncy5DT05GSUdfTk9UX0xPQURFRCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLmlzSW52YWxpZENvbmZpZyA9IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxuICBzZXROdW1iZXJPZkRlbGV0ZUljb24oKTogdm9pZCB7XHJcbiAgICBjb25zdCBjb25maWcgPSB0aGlzLmNvbmZpZ3VyYXRpb247XHJcbiAgICBpZiAodGhpcy5pc0ludmFsaWRDb25maWcgfHwgY29uZmlnLm51bWJlck9mRGVsZXRlSWNvbiA9PT0gMikge1xyXG4gICAgICB0aGlzLm51bWJlck9mRGVsZXRlSWNvbiA9IENvbnN0YW50cy5OVU1CRVJfT0ZfREVMRVRFX0lDT05TO1xyXG4gICAgfSBlbHNle1xyXG4gICAgICB0aGlzLm51bWJlck9mRGVsZXRlSWNvbiA9IG51bGw7XHJcbiAgICB9XHJcbiAgfVxyXG4gIHNldHNsaWRlVGhyZXNob2xkKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuaXNJbnZhbGlkQ29uZmlnKSB7XHJcbiAgICAgIHRoaXMuc2xpZGVUaHJlc2hvbGQgPSBDb25zdGFudHMuREVGQVVMVF9TTElERV9USFJFU0hPTEQ7XHJcbiAgICAgIHRoaXMubG9nV2FybmluZ3MoV2FybmluZ3MuU0xJREVfVEhSRVNIT0xEX05PVF9GT1VORCwgYCR7Q29uc3RhbnRzLkFERElOR19ERUZBVUxUX1NMSURFX1RIUkVTSE9MRH0gJHtDb25zdGFudHMuREVGQVVMVF9TTElERV9USFJFU0hPTER9JS5gKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgY29uc3QgY29uZmlnID0gdGhpcy5jb25maWd1cmF0aW9uO1xyXG4gICAgaWYgKGNvbmZpZy5zbGlkZVRocmVzaG9sZCA9PT0gbnVsbCB8fCBjb25maWcuc2xpZGVUaHJlc2hvbGQgPT09IHVuZGVmaW5lZCB8fCB0eXBlb2YgY29uZmlnLnNsaWRlVGhyZXNob2xkICE9PSAnbnVtYmVyJykge1xyXG4gICAgICBpZiAodHlwZW9mIGNvbmZpZy5zbGlkZVRocmVzaG9sZCAhPT0gJ251bWJlcicpIHtcclxuICAgICAgICB0aGlzLmxvZ1dhcm5pbmdzKFdhcm5pbmdzLklOVkFMSURfU0xJREVfVEhSRVNIT0xEX05PVF9BTExPV0VELCBgJHtDb25zdGFudHMuQURESU5HX0RFRkFVTFRfU0xJREVfVEhSRVNIT0xEfSAke0NvbnN0YW50cy5ERUZBVUxUX1NMSURFX1RIUkVTSE9MRH0lLmApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRoaXMubG9nV2FybmluZ3MoV2FybmluZ3MuU0xJREVfVEhSRVNIT0xEX05PVF9GT1VORCwgYCR7Q29uc3RhbnRzLkFERElOR19ERUZBVUxUX1NMSURFX1RIUkVTSE9MRH0gJHtDb25zdGFudHMuREVGQVVMVF9TTElERV9USFJFU0hPTER9JS5gKTtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLnNsaWRlVGhyZXNob2xkID0gQ29uc3RhbnRzLkRFRkFVTFRfU0xJREVfVEhSRVNIT0xEO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgaWYgKGNvbmZpZy5zbGlkZVRocmVzaG9sZCA8IENvbnN0YW50cy5NSU5fU0xJREVfVEhSRVNIT0xEIHx8IGNvbmZpZy5zbGlkZVRocmVzaG9sZCA9PT0gQ29uc3RhbnRzLk1JTl9TTElERV9USFJFU0hPTEQgfHwgY29uZmlnLnNsaWRlVGhyZXNob2xkID4gQ29uc3RhbnRzLk1BWF9TTElERV9USFJFU0hPTEQpIHtcclxuICAgICAgICBpZiAoY29uZmlnLnNsaWRlVGhyZXNob2xkID4gQ29uc3RhbnRzLk1BWF9TTElERV9USFJFU0hPTEQpIHtcclxuICAgICAgICAgIHRoaXMubG9nV2FybmluZ3MoV2FybmluZ3MuTUFYX1NMSURFX1RIUkVTSE9MRF9OT1RfQUxMT1dFRCwgYCR7Q29uc3RhbnRzLkFERElOR19ERUZBVUxUX1NMSURFX1RIUkVTSE9MRH0gJHtDb25zdGFudHMuREVGQVVMVF9TTElERV9USFJFU0hPTER9JS5gKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKGNvbmZpZy5zbGlkZVRocmVzaG9sZCA8IENvbnN0YW50cy5NSU5fU0xJREVfVEhSRVNIT0xEIHx8IGNvbmZpZy5zbGlkZVRocmVzaG9sZCA9PT0gQ29uc3RhbnRzLk1JTl9TTElERV9USFJFU0hPTEQpIHtcclxuICAgICAgICAgIHRoaXMubG9nV2FybmluZ3MoV2FybmluZ3MuWkVST19TTElERV9USFJFU0hPTERfTk9UX0FMTE9XRUQsIGAke0NvbnN0YW50cy5BRERJTkdfREVGQVVMVF9TTElERV9USFJFU0hPTER9ICR7Q29uc3RhbnRzLkRFRkFVTFRfU0xJREVfVEhSRVNIT0xEfSUuYCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuc2xpZGVUaHJlc2hvbGQgPSBDb25zdGFudHMuREVGQVVMVF9TTElERV9USFJFU0hPTEQ7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhpcy5zbGlkZVRocmVzaG9sZCA9IGNvbmZpZy5zbGlkZVRocmVzaG9sZDtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuICBzZXRsaXN0VHlwZSgpOiB2b2lkIHtcclxuICAgIGNvbnN0IGNvbmZpZyA9IHRoaXMuY29uZmlndXJhdGlvbjtcclxuICAgIGlmICh0aGlzLmlzSW52YWxpZENvbmZpZyB8fCBjb25maWcubGlzdFR5cGUgPT09IGBgIHx8IGNvbmZpZy5saXN0VHlwZSA9PT0gdW5kZWZpbmVkIHx8IGNvbmZpZy5saXN0VHlwZSA9PT0gbnVsbCkge1xyXG4gICAgICB0aGlzLmxpc3RUeXBlID0gTGlzdFR5cGUuU0lOR0xFTElORTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGNvbnN0IGxpc3RUeXBlID0gY29uZmlnLmxpc3RUeXBlLnRyaW0oKTtcclxuICAgICAgc3dpdGNoIChsaXN0VHlwZSkge1xyXG4gICAgICAgIGNhc2UgTGlzdFR5cGUuU0lOR0xFTElORTpcclxuICAgICAgICBjYXNlIExpc3RUeXBlLk1VTFRJTElORTpcclxuICAgICAgICBjYXNlIExpc3RUeXBlLkxJU1RXSVRISUNPTjpcclxuICAgICAgICBjYXNlIExpc3RUeXBlLkxJU1RXSVRISU1BR0U6XHJcbiAgICAgICAgICB0aGlzLmxpc3RUeXBlID0gbGlzdFR5cGU7XHJcbiAgICAgICAgICBicmVhaztcclxuICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgdGhpcy5saXN0VHlwZSA9IExpc3RUeXBlLlNJTkdMRUxJTkU7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbiAgc2V0RGlzYWJsZVdhcm5pbmdzKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuaXNJbnZhbGlkQ29uZmlnKSB7XHJcbiAgICAgIHRoaXMuZGlzYWJsZVdhcm5pbmdzID0gZmFsc2U7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjb25zdCBjb25maWcgPSB0aGlzLmNvbmZpZ3VyYXRpb247XHJcbiAgICAgIHRoaXMuZGlzYWJsZVdhcm5pbmdzID0gKGNvbmZpZy5kaXNhYmxlV2FybmluZ3MgJiYgY29uZmlnLmRpc2FibGVXYXJuaW5ncyAhPT0gdW5kZWZpbmVkICYmIGNvbmZpZy5kaXNhYmxlV2FybmluZ3MgIT09IG51bGwpID8gdHJ1ZSA6IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxuICBnZXRDbGFzc05hbWUoKTogc3RyaW5ne1xyXG4gICAgaWYgKHRoaXMuaXNJbnZhbGlkQ29uZmlnKSB7XHJcbiAgICAgIHJldHVybiBgJHtDb25zdGFudHMuREVGQVVMVF9DTEFTU19OQU1FfWA7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBpZiAodGhpcy5jb25maWd1cmF0aW9uLmNsYXNzbmFtZSAhPT0gJycgJiYgdGhpcy5jb25maWd1cmF0aW9uLmNsYXNzbmFtZSAhPT0gbnVsbCAmJiB0aGlzLmNvbmZpZ3VyYXRpb24uY2xhc3NuYW1lICE9PSB1bmRlZmluZWQgKXtcclxuICAgICAgICByZXR1cm4gYCR7Q29uc3RhbnRzLkRFRkFVTFRfQ0xBU1NfTkFNRX0gJHt0aGlzLmNvbmZpZ3VyYXRpb24uY2xhc3NuYW1lfWA7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgcmV0dXJuIGAke0NvbnN0YW50cy5ERUZBVUxUX0NMQVNTX05BTUV9YDtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuICBwYW5lbmQoYWN0aW9uLCBpbmRleCwgZWxlbWVudFJlZnJlbmNlKTogdm9pZCB7XHJcbiAgICBjb25zdCBjdXJyZW50TWFyZ2luID0gdGhpcy5nZXRMZWZ0UG9zaXRpb24oZWxlbWVudFJlZnJlbmNlKTtcclxuICAgIGlmIChjdXJyZW50TWFyZ2luID4gdGhpcy5zbGlkZVRocmVzaG9sZCB8fCBcclxuICAgICAgICAoY3VycmVudE1hcmdpbiA8IC0gdGhpcy5zbGlkZVRocmVzaG9sZCAmJiAgdGhpcy5udW1iZXJPZkRlbGV0ZUljb24gPT09IENvbnN0YW50cy5OVU1CRVJfT0ZfREVMRVRFX0lDT05TKSkge1xyXG4gICAgICB0aGlzLnJlbW92ZUVsZW1lbnQoaW5kZXgpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5uZ3N0ZEluZGV4TnVtYmVyID0gaW5kZXg7XHJcbiAgICB9XHJcbiAgfVxyXG4gIHBhbm1vdmUoYWN0aW9uLCBlbGVtZW50UmVmcmVuY2UpOiB2b2lkIHtcclxuICAgIGVsZW1lbnRSZWZyZW5jZS5zdHlsZS5sZWZ0ID0gYWN0aW9uLmRlbHRhWCArICdweCc7XHJcbiAgICBlbGVtZW50UmVmcmVuY2Uub2Zmc2V0TGVmdCA+IDAgPyB0aGlzLmVsZW1lbnRMZWZ0U2lnbiA9IHRydWUgOiB0aGlzLmVsZW1lbnRMZWZ0U2lnbiA9IGZhbHNlO1xyXG4gIH1cclxuICBhbGlnbkNvbXBsZXRlKGV2ZW50KTogdm9pZCB7XHJcbiAgICBldmVudC5lbGVtZW50LnN0eWxlLmxlZnQgPSAnMHB4JztcclxuICAgIGV2ZW50LmVsZW1lbnQub2Zmc2V0TGVmdCA+IDAgPyB0aGlzLmVsZW1lbnRMZWZ0U2lnbiA9IHRydWUgOiB0aGlzLmVsZW1lbnRMZWZ0U2lnbiA9IGZhbHNlO1xyXG4gICAgdGhpcy5uZ3N0ZEluZGV4TnVtYmVyID0gbnVsbDtcclxuICB9XHJcbiAgZ2V0TGVmdFNpZ24oKSB7XHJcbiAgICByZXR1cm4gdGhpcy5lbGVtZW50TGVmdFNpZ24gPyAgdHJ1ZSA6IGZhbHNlO1xyXG4gIH1cclxuICByZW1vdmVFbGVtZW50KGluZGV4KTogdm9pZCB7XHJcbiAgICBjb25zdCBkZWxldGVkSXRlbSA9IHRoaXMuaXRlbXNbaW5kZXhdO1xyXG4gICAgdGhpcy5pdGVtcy5zcGxpY2UoaW5kZXgsIDEpO1xyXG4gICAgdGhpcy5kZWxldGVkSXRlbS5lbWl0KGRlbGV0ZWRJdGVtKTtcclxuICB9XHJcbiAgZ2V0TGVmdFBvc2l0aW9uKGVsZW1lbnRSZWZyZW5jZSk6IG51bWJlciB7XHJcbiAgICBjb25zdCBjdXJyZW50bGVmdFBvc2l0aW9uID0gZWxlbWVudFJlZnJlbmNlLnN0eWxlLmxlZnQuc2xpY2UoMCwgLTIpO1xyXG4gICAgaWYgKGN1cnJlbnRsZWZ0UG9zaXRpb24gIT09IG51bGwpIHtcclxuICAgICAgcmV0dXJuIChwYXJzZUludChcclxuICAgICAgICBjdXJyZW50bGVmdFBvc2l0aW9uLCAxMFxyXG4gICAgICApICogMTAwKSAvIHdpbmRvdy5pbm5lcldpZHRoO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgcmV0dXJuIDA7XHJcbiAgICB9XHJcbiAgfVxyXG4gIGxvZ1dhcm5pbmdzKHdhcm5pbmdGb3I6IHN0cmluZywgZXh0cmFNZXNzYWdlOiBhbnkgPSBudWxsKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5kaXNhYmxlV2FybmluZ3MpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgc3dpdGNoICh3YXJuaW5nRm9yKSB7XHJcbiAgICAgIGNhc2UgV2FybmluZ3MuQ09ORklHX05PVF9MT0FERUQ6XHJcbiAgICAgIGNhc2UgV2FybmluZ3MuU0xJREVfVEhSRVNIT0xEX05PVF9GT1VORDpcclxuICAgICAgY2FzZSBXYXJuaW5ncy5aRVJPX1NMSURFX1RIUkVTSE9MRF9OT1RfQUxMT1dFRDpcclxuICAgICAgY2FzZSBXYXJuaW5ncy5NQVhfU0xJREVfVEhSRVNIT0xEX05PVF9BTExPV0VEOlxyXG4gICAgICBjYXNlIFdhcm5pbmdzLklOVkFMSURfU0xJREVfVEhSRVNIT0xEX05PVF9BTExPV0VEOlxyXG4gICAgICAgIGV4dHJhTWVzc2FnZSA9PT0gbnVsbCA/IGNvbnNvbGUud2Fybih0aGlzLmdldENvbnN0VmFsdWUod2FybmluZ0ZvcikpIDogY29uc29sZS53YXJuKHRoaXMuZ2V0Q29uc3RWYWx1ZSh3YXJuaW5nRm9yKSwgZXh0cmFNZXNzYWdlKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgZGVmYXVsdDpcclxuICAgICAgICAvLyB1bmljb25zICFcclxuICAgIH1cclxuICB9XHJcbiAgZ2V0Q29uc3RWYWx1ZShjb25zdGFudE5hbWU6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gQ29uc3RhbnRzW2NvbnN0YW50TmFtZV07XHJcbiAgfVxyXG59XHJcbiIsIi8qISAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5Db3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cclxuTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTsgeW91IG1heSBub3QgdXNlXHJcbnRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlXHJcbkxpY2Vuc2UgYXQgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXHJcblxyXG5USElTIENPREUgSVMgUFJPVklERUQgT04gQU4gKkFTIElTKiBCQVNJUywgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZXHJcbktJTkQsIEVJVEhFUiBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBXSVRIT1VUIExJTUlUQVRJT04gQU5ZIElNUExJRURcclxuV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIFRJVExFLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSxcclxuTUVSQ0hBTlRBQkxJVFkgT1IgTk9OLUlORlJJTkdFTUVOVC5cclxuXHJcblNlZSB0aGUgQXBhY2hlIFZlcnNpb24gMi4wIExpY2Vuc2UgZm9yIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9uc1xyXG5hbmQgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXHJcbi8qIGdsb2JhbCBSZWZsZWN0LCBQcm9taXNlICovXHJcblxyXG52YXIgZXh0ZW5kU3RhdGljcyA9IE9iamVjdC5zZXRQcm90b3R5cGVPZiB8fFxyXG4gICAgKHsgX19wcm90b19fOiBbXSB9IGluc3RhbmNlb2YgQXJyYXkgJiYgZnVuY3Rpb24gKGQsIGIpIHsgZC5fX3Byb3RvX18gPSBiOyB9KSB8fFxyXG4gICAgZnVuY3Rpb24gKGQsIGIpIHsgZm9yICh2YXIgcCBpbiBiKSBpZiAoYi5oYXNPd25Qcm9wZXJ0eShwKSkgZFtwXSA9IGJbcF07IH07XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19leHRlbmRzKGQsIGIpIHtcclxuICAgIGV4dGVuZFN0YXRpY3MoZCwgYik7XHJcbiAgICBmdW5jdGlvbiBfXygpIHsgdGhpcy5jb25zdHJ1Y3RvciA9IGQ7IH1cclxuICAgIGQucHJvdG90eXBlID0gYiA9PT0gbnVsbCA/IE9iamVjdC5jcmVhdGUoYikgOiAoX18ucHJvdG90eXBlID0gYi5wcm90b3R5cGUsIG5ldyBfXygpKTtcclxufVxyXG5cclxuZXhwb3J0IHZhciBfX2Fzc2lnbiA9IE9iamVjdC5hc3NpZ24gfHwgZnVuY3Rpb24gX19hc3NpZ24odCkge1xyXG4gICAgZm9yICh2YXIgcywgaSA9IDEsIG4gPSBhcmd1bWVudHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XHJcbiAgICAgICAgcyA9IGFyZ3VtZW50c1tpXTtcclxuICAgICAgICBmb3IgKHZhciBwIGluIHMpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocywgcCkpIHRbcF0gPSBzW3BdO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHQ7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3Jlc3QocywgZSkge1xyXG4gICAgdmFyIHQgPSB7fTtcclxuICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSAmJiBlLmluZGV4T2YocCkgPCAwKVxyXG4gICAgICAgIHRbcF0gPSBzW3BdO1xyXG4gICAgaWYgKHMgIT0gbnVsbCAmJiB0eXBlb2YgT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyA9PT0gXCJmdW5jdGlvblwiKVxyXG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBwID0gT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhzKTsgaSA8IHAubGVuZ3RoOyBpKyspIGlmIChlLmluZGV4T2YocFtpXSkgPCAwKVxyXG4gICAgICAgICAgICB0W3BbaV1dID0gc1twW2ldXTtcclxuICAgIHJldHVybiB0O1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19kZWNvcmF0ZShkZWNvcmF0b3JzLCB0YXJnZXQsIGtleSwgZGVzYykge1xyXG4gICAgdmFyIGMgPSBhcmd1bWVudHMubGVuZ3RoLCByID0gYyA8IDMgPyB0YXJnZXQgOiBkZXNjID09PSBudWxsID8gZGVzYyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodGFyZ2V0LCBrZXkpIDogZGVzYywgZDtcclxuICAgIGlmICh0eXBlb2YgUmVmbGVjdCA9PT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgUmVmbGVjdC5kZWNvcmF0ZSA9PT0gXCJmdW5jdGlvblwiKSByID0gUmVmbGVjdC5kZWNvcmF0ZShkZWNvcmF0b3JzLCB0YXJnZXQsIGtleSwgZGVzYyk7XHJcbiAgICBlbHNlIGZvciAodmFyIGkgPSBkZWNvcmF0b3JzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSBpZiAoZCA9IGRlY29yYXRvcnNbaV0pIHIgPSAoYyA8IDMgPyBkKHIpIDogYyA+IDMgPyBkKHRhcmdldCwga2V5LCByKSA6IGQodGFyZ2V0LCBrZXkpKSB8fCByO1xyXG4gICAgcmV0dXJuIGMgPiAzICYmIHIgJiYgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwga2V5LCByKSwgcjtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcGFyYW0ocGFyYW1JbmRleCwgZGVjb3JhdG9yKSB7XHJcbiAgICByZXR1cm4gZnVuY3Rpb24gKHRhcmdldCwga2V5KSB7IGRlY29yYXRvcih0YXJnZXQsIGtleSwgcGFyYW1JbmRleCk7IH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fbWV0YWRhdGEobWV0YWRhdGFLZXksIG1ldGFkYXRhVmFsdWUpIHtcclxuICAgIGlmICh0eXBlb2YgUmVmbGVjdCA9PT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgUmVmbGVjdC5tZXRhZGF0YSA9PT0gXCJmdW5jdGlvblwiKSByZXR1cm4gUmVmbGVjdC5tZXRhZGF0YShtZXRhZGF0YUtleSwgbWV0YWRhdGFWYWx1ZSk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2F3YWl0ZXIodGhpc0FyZywgX2FyZ3VtZW50cywgUCwgZ2VuZXJhdG9yKSB7XHJcbiAgICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcclxuICAgICAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3JbXCJ0aHJvd1wiXSh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gc3RlcChyZXN1bHQpIHsgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkgeyByZXNvbHZlKHJlc3VsdC52YWx1ZSk7IH0pLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7IH1cclxuICAgICAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XHJcbiAgICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZ2VuZXJhdG9yKHRoaXNBcmcsIGJvZHkpIHtcclxuICAgIHZhciBfID0geyBsYWJlbDogMCwgc2VudDogZnVuY3Rpb24oKSB7IGlmICh0WzBdICYgMSkgdGhyb3cgdFsxXTsgcmV0dXJuIHRbMV07IH0sIHRyeXM6IFtdLCBvcHM6IFtdIH0sIGYsIHksIHQsIGc7XHJcbiAgICByZXR1cm4gZyA9IHsgbmV4dDogdmVyYigwKSwgXCJ0aHJvd1wiOiB2ZXJiKDEpLCBcInJldHVyblwiOiB2ZXJiKDIpIH0sIHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiAoZ1tTeW1ib2wuaXRlcmF0b3JdID0gZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzOyB9KSwgZztcclxuICAgIGZ1bmN0aW9uIHZlcmIobikgeyByZXR1cm4gZnVuY3Rpb24gKHYpIHsgcmV0dXJuIHN0ZXAoW24sIHZdKTsgfTsgfVxyXG4gICAgZnVuY3Rpb24gc3RlcChvcCkge1xyXG4gICAgICAgIGlmIChmKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiR2VuZXJhdG9yIGlzIGFscmVhZHkgZXhlY3V0aW5nLlwiKTtcclxuICAgICAgICB3aGlsZSAoXykgdHJ5IHtcclxuICAgICAgICAgICAgaWYgKGYgPSAxLCB5ICYmICh0ID0gb3BbMF0gJiAyID8geVtcInJldHVyblwiXSA6IG9wWzBdID8geVtcInRocm93XCJdIHx8ICgodCA9IHlbXCJyZXR1cm5cIl0pICYmIHQuY2FsbCh5KSwgMCkgOiB5Lm5leHQpICYmICEodCA9IHQuY2FsbCh5LCBvcFsxXSkpLmRvbmUpIHJldHVybiB0O1xyXG4gICAgICAgICAgICBpZiAoeSA9IDAsIHQpIG9wID0gW29wWzBdICYgMiwgdC52YWx1ZV07XHJcbiAgICAgICAgICAgIHN3aXRjaCAob3BbMF0pIHtcclxuICAgICAgICAgICAgICAgIGNhc2UgMDogY2FzZSAxOiB0ID0gb3A7IGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgY2FzZSA0OiBfLmxhYmVsKys7IHJldHVybiB7IHZhbHVlOiBvcFsxXSwgZG9uZTogZmFsc2UgfTtcclxuICAgICAgICAgICAgICAgIGNhc2UgNTogXy5sYWJlbCsrOyB5ID0gb3BbMV07IG9wID0gWzBdOyBjb250aW51ZTtcclxuICAgICAgICAgICAgICAgIGNhc2UgNzogb3AgPSBfLm9wcy5wb3AoKTsgXy50cnlzLnBvcCgpOyBjb250aW51ZTtcclxuICAgICAgICAgICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCEodCA9IF8udHJ5cywgdCA9IHQubGVuZ3RoID4gMCAmJiB0W3QubGVuZ3RoIC0gMV0pICYmIChvcFswXSA9PT0gNiB8fCBvcFswXSA9PT0gMikpIHsgXyA9IDA7IGNvbnRpbnVlOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9wWzBdID09PSAzICYmICghdCB8fCAob3BbMV0gPiB0WzBdICYmIG9wWzFdIDwgdFszXSkpKSB7IF8ubGFiZWwgPSBvcFsxXTsgYnJlYWs7IH1cclxuICAgICAgICAgICAgICAgICAgICBpZiAob3BbMF0gPT09IDYgJiYgXy5sYWJlbCA8IHRbMV0pIHsgXy5sYWJlbCA9IHRbMV07IHQgPSBvcDsgYnJlYWs7IH1cclxuICAgICAgICAgICAgICAgICAgICBpZiAodCAmJiBfLmxhYmVsIDwgdFsyXSkgeyBfLmxhYmVsID0gdFsyXTsgXy5vcHMucHVzaChvcCk7IGJyZWFrOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRbMl0pIF8ub3BzLnBvcCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIF8udHJ5cy5wb3AoKTsgY29udGludWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgb3AgPSBib2R5LmNhbGwodGhpc0FyZywgXyk7XHJcbiAgICAgICAgfSBjYXRjaCAoZSkgeyBvcCA9IFs2LCBlXTsgeSA9IDA7IH0gZmluYWxseSB7IGYgPSB0ID0gMDsgfVxyXG4gICAgICAgIGlmIChvcFswXSAmIDUpIHRocm93IG9wWzFdOyByZXR1cm4geyB2YWx1ZTogb3BbMF0gPyBvcFsxXSA6IHZvaWQgMCwgZG9uZTogdHJ1ZSB9O1xyXG4gICAgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19leHBvcnRTdGFyKG0sIGV4cG9ydHMpIHtcclxuICAgIGZvciAodmFyIHAgaW4gbSkgaWYgKCFleHBvcnRzLmhhc093blByb3BlcnR5KHApKSBleHBvcnRzW3BdID0gbVtwXTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fdmFsdWVzKG8pIHtcclxuICAgIHZhciBtID0gdHlwZW9mIFN5bWJvbCA9PT0gXCJmdW5jdGlvblwiICYmIG9bU3ltYm9sLml0ZXJhdG9yXSwgaSA9IDA7XHJcbiAgICBpZiAobSkgcmV0dXJuIG0uY2FsbChvKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgICAgbmV4dDogZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAobyAmJiBpID49IG8ubGVuZ3RoKSBvID0gdm9pZCAwO1xyXG4gICAgICAgICAgICByZXR1cm4geyB2YWx1ZTogbyAmJiBvW2krK10sIGRvbmU6ICFvIH07XHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcmVhZChvLCBuKSB7XHJcbiAgICB2YXIgbSA9IHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiBvW1N5bWJvbC5pdGVyYXRvcl07XHJcbiAgICBpZiAoIW0pIHJldHVybiBvO1xyXG4gICAgdmFyIGkgPSBtLmNhbGwobyksIHIsIGFyID0gW10sIGU7XHJcbiAgICB0cnkge1xyXG4gICAgICAgIHdoaWxlICgobiA9PT0gdm9pZCAwIHx8IG4tLSA+IDApICYmICEociA9IGkubmV4dCgpKS5kb25lKSBhci5wdXNoKHIudmFsdWUpO1xyXG4gICAgfVxyXG4gICAgY2F0Y2ggKGVycm9yKSB7IGUgPSB7IGVycm9yOiBlcnJvciB9OyB9XHJcbiAgICBmaW5hbGx5IHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBpZiAociAmJiAhci5kb25lICYmIChtID0gaVtcInJldHVyblwiXSkpIG0uY2FsbChpKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZmluYWxseSB7IGlmIChlKSB0aHJvdyBlLmVycm9yOyB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gYXI7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3NwcmVhZCgpIHtcclxuICAgIGZvciAodmFyIGFyID0gW10sIGkgPSAwOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKVxyXG4gICAgICAgIGFyID0gYXIuY29u