chain-able
Version:
interfaces that describe their intentions.
709 lines (626 loc) • 62.8 kB
JavaScript
/**
* @TODO clarify .set vs .call
* {@link https://github.com/iluwatar/java-design-patterns/tree/master/property property-pattern}
* {@link https://github.com/iluwatar/java-design-patterns/tree/master/prototype prototype-pattern}
* {@link https://github.com/iluwatar/java-design-patterns/tree/master/step-builder step-builder-pattern}
* {@link https://github.com/iluwatar/java-design-patterns/tree/master/builder builder-pattern}
* {@link https://github.com/addyosmani/essential-js-design-patterns/blob/master/diagrams/mixins.png mixin-png}
* {@link https://sourcemaking.com/design_patterns/creational_patterns creational-patterns}
* {@link https://sourcemaking.com/design_patterns/factory_method factory-method}
* {@link https://medium.com/javascript-scene/javascript-factory-functions-vs-constructor-functions-vs-classes-2f22ceddf33e constructors}
* {@link https://www.sitepoint.com/factory-functions-javascript/ js-factory-functions}
*/
/* eslint complexity: "OFF" */
/* eslint import/max-dependencies: "OFF" */
// core
var ChainedMap = require('./ChainedMapBase')
var SHORTHANDS_KEY = require('./deps/meta/shorthands')
var ENV_DEVELOPMENT = require('./deps/env/dev')
var ENV_DEBUG = require('./deps/env/debug')
// plugins
var schemaMethod = require('./plugins/schema')
var typesPlugin = require('./plugins/types')
var objPlugin = require('./plugins/obj')
var encasePlugin = require('./plugins/encase')
var decoratePlugin = require('./plugins/decorate')
var autoIncrementPlugin = require('./plugins/autoIncrement')
var autoGetSetPlugin = require('./plugins/autoGetSet')
// const validatorBuilder = require('./deps/validators/validatorBuilder')
// obj
var hasOwnProperty = require('./deps/util/hasOwnProperty')
var getDescriptor = require('./deps/util/getDescriptor')
var ObjectDefine = require('./deps/define')
var ObjectKeys = require('./deps/util/keys')
var ObjectAssign = require('./deps/util/assign')
// utils
var toarr = require('./deps/to-arr')
var argumentor = require('./deps/argumentor')
var camelCase = require('./deps/camel-case')
var markForGarbageCollection = require('./deps/gc')
// is
var isObj = require('./deps/is/obj')
var isArray = require('./deps/is/array')
var isUndefined = require('./deps/is/undefined')
var isTrue = require('./deps/is/true')
var isFalse = require('./deps/is/false')
var isObjWithKeys = require('./deps/is/objWithKeys')
var DEFAULTED_KEY = 'defaulted'
var METHOD_KEYS = [
'onInvalid',
'onValid',
'initial',
'default',
'type',
'callReturns',
'target',
'onSet',
'onCall',
'onGet',
]
// const SET_KEY = METHOD_KEYS[0]
function getSetFactory(_this, name, desc) {
_this[camelCase(("set-" + name))] = desc.set
_this[camelCase(("get-" + name))] = desc.get
}
function aliasFactory(name, parent, aliases) {
if (!isUndefined(aliases)) {
for (var a = 0; a < aliases.length; a++) {
ObjectDefine(parent, aliases[a], getDescriptor(parent, name))
}
}
}
// @TODO: to use as a function
// function _methods() {}
// _methods.use(obj) {
// this.obj = obj
// return _methods
// }
// _methods.extend = _methods.use
// _methods.methods = function(methods) {
// return new MethodChain(this.obj)
// }
var methodFactories
/**
* @member MethodChain
* @inheritdoc
* @class
* @extends {ChainedMap}
* @type {Map}
*
* @since 4.0.0
*
* @TODO maybe abstract the most re-usable core as a protected class
* so the shorthands could be used, and more functionality made external
* @TODO need to separate schema from here as external functionality & add .add
* @TODO .prop - for things on the instance, not in the store?
* !!! .sponge - absorn properties into the store
*/
var MethodChain = (function (ChainedMap) {
function MethodChain(parent) {
var this$1 = this;
// timer.start('methodchain')
ChainedMap.call(this, parent)
// ----------------
var set = this.set.bind(this)
this.newThis = function () { return new MethodChain(parent); }
this.toNumber = function () { return this$1.build(0); }
this.extend(METHOD_KEYS)
// shorthand
this.method = this.methods = function (name) {
if (!this$1.length) { return this$1.name(name) }
return this$1.build().methods(name)
}
// default argument...
this.encase = function (x) {
return set('encase', parent[x] || x || true)
}
// alias
this.then = this.onValid.bind(this)
this.catch = this.onInvalid.bind(this)
this.returns = function (x, callReturns) { return set('returns', x || parent).callReturns(callReturns); }
// @NOTE replaces shorthands.chainWrap
this.chainable = this.returns
/**
* @desc alias methods
* @since 2.0.0
*
* @param {string | Array<string>} aliases aliases to remap to the current method being built
* @return {MethodChain} @chainable
*
* @NOTE these would be .transform
*
* @example
*
* const chain = new Chain()
* chain.methods(['canada']).alias(['eh']).build()
* chain.eh('actually...canada o.o')
* chain.get('canada')
* //=> 'actually...canada o.o')
*
*/
this.alias = function (aliases) { return this$1.tap('alias', function (old, merge) { return merge(old, toarr(aliases)); }); }
this.plugin = function (plugin) { return this$1.tap('plugins', function (old, merge) { return merge(old, toarr(plugin)); }); }
this.camelCase = function () { return set('camel', true); }
// @NOTE: x = true is much prettier, but compiles badly
var defaultToTrue = function (x) { return (isUndefined(x) ? true : x); }
this.define = function (x) { return set('define', defaultToTrue(x)); }
this.getSet = function (x) { return set('getSet', defaultToTrue(x)); }
// @TODO: unless these use scoped vars, they should be on proto
// @NOTE shorthands.bindMethods
this.bind = function (target) { return set('bind', isUndefined(target) ? parent : target); }
this.autoGetSet = function () { return this$1.plugin(autoGetSetPlugin); }
this.plugin(typesPlugin)
if (isObjWithKeys(methodFactories)) {
ObjectKeys(methodFactories).forEach(function (factoryName) {
this$1[factoryName] = function (arg) { return methodFactories[factoryName].call(this$1, arg); }
if (ENV_DEVELOPMENT) {
this$1[factoryName].methodFactory = true
}
})
}
}
if ( ChainedMap ) MethodChain.__proto__ = ChainedMap;
MethodChain.prototype = Object.create( ChainedMap && ChainedMap.prototype );
MethodChain.prototype.constructor = MethodChain;
/**
* @desc setup methods to build
* @category builder
* @memberOf MethodChain
*
* @since 4.0.0-beta.1 <- moved to plugin
* @since 4.0.0
*
* @param {string | Object | Array<string>} methods method names to build
* @return {MethodChain} @chainable
*
* @example
*
* var obj = {}
* new MethodChain(obj).name('eh').build()
* typeof obj.eh
* //=> 'function'
*
*/
MethodChain.prototype.name = function name (methods) {
var this$1 = this;
var names = methods
/**
* @desc this is a plugin for building methods
* schema defaults value to `.type`
* this defaults values to `.onCall`
*/
if (!isArray(methods) && isObj(methods)) {
names = ObjectKeys(methods)
for (var name = 0; name < names.length; name++) {
this$1.plugin(objPlugin.call(this$1, methods, names[name]))
}
}
return this.set('names', names)
};
/**
* @since 4.0.0-beta.1 <- moved to plugin
* @since 4.0.0
*
* @category types
* @memberOf MethodChain
*
* @param {Object} obj schema
* @return {MethodChain} @chainable
*
* @TODO move out into a plugin to show how easy it is to use a plugin
* and make it able to be split out for size when needed
*
* @TODO inherit properties (in plugin, for each key)
* from this for say, dotProp, getSet
*
* @TODO very @important
* that we setup schema validation at the highest root for validation
* and then have some demo for how to validate on set using say mobx
* observables for all the way down...
*/
MethodChain.prototype.schema = function schema (obj) {
return schemaMethod.call(this, obj)
};
/**
* @desc set the actual method, also need .context - use .parent
* @memberOf MethodChain
* @since 4.0.0
*
* @param {any} [returnValue=undefined] returned at the end of the function for ease of use
* @return {MethodChain} @chainable
*
* @TODO if passing in a name that already exists, operations are decorations... (partially done)
* @see https://github.com/iluwatar/java-design-patterns/tree/master/step-builder
*
* @example
* var obj = {}
* const one = new MethodChain(obj).methods('eh').getSet().build(1)
* //=> 1
*
* typeof obj.getEh
* //=> 'function'
*/
MethodChain.prototype.build = function build (returnValue) {
var this$1 = this;
var parent = this.parent
var names = toarr(this.get('names'))
var shouldTapName = this.get('camel')
for (var name = 0; name < names.length; name++) {
this$1._build(shouldTapName ? camelCase(names[name]) : names[name], parent)
}
// timer.stop('methodchain').log('methodchain').start('gc')
// remove refs to unused
this.clear()
delete this.parent
markForGarbageCollection(this)
// very fast - timer & ensuring props are cleaned
// timer.stop('gc').log('gc')
// require('fliplog').quick(this)
return isUndefined(returnValue) ? parent : returnValue
};
/**
* @memberOf MethodChain
*
* @since 4.0.0
* @protected
* @param {Primitive} name method name
* @param {Object} parent being decorated
* @param {Object} built method being built
* @return {void}
*
* @TODO optimize the size of this
* with some bitwise operators
* hashing the things that have been defaulted
* also could be plugin
*
* @example
* ._defaults('', {}, {})
*/
MethodChain.prototype._defaults = function _defaults (name, parent, built) {
// defaults
var defaultOnSet = function (arg) { return parent.set(name, arg); }
var defaultOnGet = function () { return parent.get(name); }
// so we know if we defaulted them
defaultOnSet[DEFAULTED_KEY] = true
defaultOnGet[DEFAULTED_KEY] = true
// when we've[DEFAULTED_KEY] already for another method,
// we need a new function,
// else the name will be scoped incorrectly
var onCall = built.onCall;
var onSet = built.onSet;
var onGet = built.onGet;
if (!onGet || onGet[DEFAULTED_KEY]) {
this.onGet(defaultOnGet)
}
if (!onCall || onCall[DEFAULTED_KEY]) {
this.onCall(defaultOnSet)
}
if (!onSet || onSet[DEFAULTED_KEY]) {
this.onSet(defaultOnSet)
}
};
/**
* @protected
* @since 4.0.0-alpha.1
* @memberOf MethodChain
*
* @param {Primitive} name
* @param {Object} parent
* @return {void}
*
* @TODO allow config of method var in plugins since it is scoped...
* @TODO add to .meta(shorthands)
* @TODO reduce complexity if perf allows
* @NOTE scoping here adding default functions have to rescope arguments
*/
MethodChain.prototype._build = function _build (name, parent) {
var this$1 = this;
var method
var existing
var entries = function () { return this$1.entries(); }
// could ternary `let method =` here
if (hasOwnProperty(parent, name)) {
existing = getDescriptor(parent, name)
// avoid `TypeError: Cannot redefine property:`
if (isFalse(existing.configurable)) {
return
}
// use existing property, when configurable
method = existing.value
if (ENV_DEVELOPMENT) {
method.decorated = true
}
this.onCall(method).onSet(method)
}
else if (parent[name]) {
method = parent[name]
if (ENV_DEVELOPMENT) {
method.decorated = true
}
this.onCall(method).onSet(method)
}
// scope it once for plugins & type building, then get it again
var built = entries()
this._defaults(name, parent, built)
// plugins can add methods,
// useful as plugins/presets & decorators for multi-name building
var instancePlugins = built.plugins
if (instancePlugins) {
for (var plugin = 0; plugin < instancePlugins.length; plugin++) {
built = entries()
instancePlugins[plugin].call(this$1, name, parent, built)
}
}
// after last plugin is finished, or defaults
built = entries()
// wrap in encasing when we have a validator or .encase
// @NOTE: validator plugin was here, moved into a plugin
if (built.encase) {
var encased = encasePlugin.call(this, name, parent, built)(method)
if (ENV_DEVELOPMENT) {
encased.encased = method
}
this.onCall(encased).onSet(encased)
method = encased
built = entries()
}
// not destructured for better variable names
var shouldAddGetterSetter = built.getSet
var shouldDefineGetSet = built.define
var defaultValue = built.default
// can only have `call` or `get/set`...
var onGet = built.onGet;
var onSet = built.onSet;
var onCall = built.onCall;
var initial = built.initial;
var bind = built.bind;
var returns = built.returns;
var callReturns = built.callReturns;
var alias = built.alias;
// default method, if we do not have one already
if (!method) {
method = function (arg) {
if ( arg === void 0 ) arg = defaultValue;
return onCall.call(parent, arg);
}
if (ENV_DEVELOPMENT) {
method.created = true
}
}
if (bind) {
// bind = bindArgument || parent
method = method.bind(bind)
}
if (returns) {
var ref = method
method = function() {
var args = argumentor.apply(null, arguments)
// eslint-disable-next-line prefer-rest-params
var result = ref.apply(parent, args)
return isTrue(callReturns)
? returns.apply(parent, [result].concat(args))
: returns
}
}
if (!isUndefined(initial)) {
parent.set(name, initial)
}
// --------------- stripped -----------
/**
* !!!!! @TODO: put in `plugins.post.call`
* !!!!! @TODO: ensure unique name
*
* can add .meta on them though for re-decorating
* -> but this has issue with .getset so needs to be on .meta[name]
*/
/* istanbul ignore next: dev */
if (ENV_DEVELOPMENT) {
ObjectDefine(onGet, 'name', {
value: camelCase(((onGet.name) + "+get-" + name)),
})
ObjectDefine(onSet, 'name', {
value: camelCase(((onSet.name) + "+set-" + name)),
})
ObjectDefine(onCall, 'name', {
value: camelCase(((onCall.name) + "+call-" + name)),
})
ObjectDefine(method, 'name', {value: camelCase(("" + name))})
if (built.type) { method.type = built.type }
if (initial) { method.initial = initial }
if (bind) { method.bound = bind }
if (returns) { method.returns = returns }
if (alias) { method.alias = alias }
if (callReturns) { method.callReturns = callReturns }
if (onGet) { method._get = onGet }
if (onSet) { method._set = onSet }
// eslint-disable-next-line
if (onCall != onCall) { method._call = onCall }
}
/* istanbul ignore next: dev */
if (ENV_DEBUG) {
console.log({
name: name,
defaultValue: defaultValue,
initial: initial,
returns: returns,
onGet: onGet,
onSet: onSet,
method: method.toString(),
})
}
// ----------------- ;stripped ------------
// @TODO: WOULD ALL BE METHOD.POST
// --- could be a method too ---
var getterSetter = {get: onGet, set: onSet}
var descriptor = shouldDefineGetSet ? getterSetter : {value: method}
if (existing) { descriptor = ObjectAssign(existing, descriptor) }
// [TypeError: Invalid property descriptor.
// Cannot both specify accessors and a value or writable attribute, #<Object>]
if (descriptor.value && descriptor.get) {
delete descriptor.value
}
if (!isUndefined(descriptor.writable)) {
delete descriptor.writable
}
var target = this.get('target') || parent
ObjectDefine(target, name, descriptor)
if (shouldAddGetterSetter) {
if (target.meta) { target.meta(SHORTHANDS_KEY, name, onSet) }
getSetFactory(target, name, getterSetter)
}
aliasFactory(name, target, alias)
// if (built.metadata) {
// target.meta(SHORTHANDS_KEY, name, set)
// }
// require('fliplog')
// .bold('decorate')
// .data({
// // t: this,
// descriptor,
// shouldDefineGetSet,
// method,
// str: method.toString(),
// // target,
// name,
// })
// .echo()
};
// ---
/**
* @desc add methods to the parent for easier chaining
* @alias extendParent
* @memberOf MethodChain
*
* @since 4.0.0-beta.1 <- moved to plugin
* @since 4.0.0 <- moved from Extend
* @since 1.0.0
*
* @param {Object} [parentToDecorate=undefined] decorate a specific parent shorthand
* @return {ChainedMap} @chainable
*
* @see plugins/decorate
* @see ChainedMap.parent
*
* @example
*
* var obj = {}
* new MethodChain({}).name('eh').decorate(obj).build()
* typeof obj.eh
* //=> 'function'
*
* @example
*
* class Decorator extends Chain {
* constructor(parent) {
* super(parent)
* this.methods(['easy']).decorate(parent).build()
* this.methods('advanced')
* .onCall(this.advanced.bind(this))
* .decorate(parent)
* .build()
* }
* advanced(arg) {
* this.set('advanced', arg)
* return this.parent
* }
* easy(arg) {
* this.parent.set('easy-peasy', arg)
* }
* }
*
* class Master extends Chain {
* constructor(parent) {
* super(parent)
* this.eh = new Decorator(this)
* }
* }
*
* const master = new Master()
*
* master.get('easy-peasy')
* //=> true
*
* master.eh.get('advanced')
* //=> 'a+'
*
* @example
*
* +chain.method('ehOh').decorate(null)
* //=> @throws Error('must provide parent argument')
*
*/
MethodChain.prototype.decorate = function decorate (parentToDecorate) {
/* istanbul ignore next: devs */
if (ENV_DEVELOPMENT) {
if (!(parentToDecorate || this.parent.parent)) {
throw new Error('must provide parent argument')
}
}
return decoratePlugin.call(this, parentToDecorate || this.parent.parent)
};
/**
* @desc adds a plugin to increment the value on every call
* @modifies this.initial
* @modifies this.onCall
*
* @memberOf MethodChain
* @since 4.0.0-beta.1 <- moved to plugin
* @since 4.0.0 <- renamed from .extendIncrement
* @since 0.4.0
*
* @return {MethodChain} @chainable
*
* @see plugins/autoIncrement
*
* @example
*
* chain.methods(['index']).autoIncrement().build().index().index(+1).index()
* chain.get('index')
* //=> 3
*
*/
MethodChain.prototype.autoIncrement = function autoIncrement () {
return this.plugin(autoIncrementPlugin)
};
return MethodChain;
}(ChainedMap));
/**
* @desc add methodFactories easily
* @static
* @since 4.0.0-beta.2
*
* @param {Object} methodFactory factories to add
* @return {void}
*
* @example
*
* function autoGetSet(name, parent) {
* const auto = arg =>
* (isUndefined(arg) ? parent.get(name) : parent.set(name, arg))
*
* //so we know if we defaulted them
* auto.autoGetSet = true
* return this.onSet(auto).onGet(auto).onCall(auto)
* }
* MethodChain.addPlugin({autoGetSet})
*
*
* const chain = new Chain()
* chain.methods('eh').autoGetSet().build()
*
* chain.eh(1)
* //=> chain
* chain.eh()
* //=> 1 *
*
*/
MethodChain.add = function addMethodFactories(methodFactory) {
ObjectAssign(methodFactories, methodFactory)
}
methodFactories = MethodChain.add
// MethodChain.addTypes = types => {
// validatorBuilder.merge(types)
// return MethodChain
// }
module.exports = MethodChain
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWV0aG9kQ2hhaW4uanMiLCJzb3VyY2VzIjpbIk1ldGhvZENoYWluLmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQFRPRE8gY2xhcmlmeSAuc2V0IHZzIC5jYWxsXG4gKiB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2lsdXdhdGFyL2phdmEtZGVzaWduLXBhdHRlcm5zL3RyZWUvbWFzdGVyL3Byb3BlcnR5IHByb3BlcnR5LXBhdHRlcm59XG4gKiB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2lsdXdhdGFyL2phdmEtZGVzaWduLXBhdHRlcm5zL3RyZWUvbWFzdGVyL3Byb3RvdHlwZSBwcm90b3R5cGUtcGF0dGVybn1cbiAqIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vaWx1d2F0YXIvamF2YS1kZXNpZ24tcGF0dGVybnMvdHJlZS9tYXN0ZXIvc3RlcC1idWlsZGVyIHN0ZXAtYnVpbGRlci1wYXR0ZXJufVxuICoge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9pbHV3YXRhci9qYXZhLWRlc2lnbi1wYXR0ZXJucy90cmVlL21hc3Rlci9idWlsZGVyIGJ1aWxkZXItcGF0dGVybn1cbiAqIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vYWRkeW9zbWFuaS9lc3NlbnRpYWwtanMtZGVzaWduLXBhdHRlcm5zL2Jsb2IvbWFzdGVyL2RpYWdyYW1zL21peGlucy5wbmcgbWl4aW4tcG5nfVxuICoge0BsaW5rIGh0dHBzOi8vc291cmNlbWFraW5nLmNvbS9kZXNpZ25fcGF0dGVybnMvY3JlYXRpb25hbF9wYXR0ZXJucyBjcmVhdGlvbmFsLXBhdHRlcm5zfVxuICoge0BsaW5rIGh0dHBzOi8vc291cmNlbWFraW5nLmNvbS9kZXNpZ25fcGF0dGVybnMvZmFjdG9yeV9tZXRob2QgZmFjdG9yeS1tZXRob2R9XG4gKiB7QGxpbmsgaHR0cHM6Ly9tZWRpdW0uY29tL2phdmFzY3JpcHQtc2NlbmUvamF2YXNjcmlwdC1mYWN0b3J5LWZ1bmN0aW9ucy12cy1jb25zdHJ1Y3Rvci1mdW5jdGlvbnMtdnMtY2xhc3Nlcy0yZjIyY2VkZGYzM2UgY29uc3RydWN0b3JzfVxuICoge0BsaW5rIGh0dHBzOi8vd3d3LnNpdGVwb2ludC5jb20vZmFjdG9yeS1mdW5jdGlvbnMtamF2YXNjcmlwdC8ganMtZmFjdG9yeS1mdW5jdGlvbnN9XG4gKi9cbi8qIGVzbGludCBjb21wbGV4aXR5OiBcIk9GRlwiICovXG4vKiBlc2xpbnQgaW1wb3J0L21heC1kZXBlbmRlbmNpZXM6IFwiT0ZGXCIgKi9cblxuLy8gY29yZVxuY29uc3QgQ2hhaW5lZE1hcCA9IHJlcXVpcmUoJy4vQ2hhaW5lZE1hcEJhc2UnKVxuY29uc3QgU0hPUlRIQU5EU19LRVkgPSByZXF1aXJlKCcuL2RlcHMvbWV0YS9zaG9ydGhhbmRzJylcbmNvbnN0IEVOVl9ERVZFTE9QTUVOVCA9IHJlcXVpcmUoJy4vZGVwcy9lbnYvZGV2JylcbmNvbnN0IEVOVl9ERUJVRyA9IHJlcXVpcmUoJy4vZGVwcy9lbnYvZGVidWcnKVxuLy8gcGx1Z2luc1xuY29uc3Qgc2NoZW1hTWV0aG9kID0gcmVxdWlyZSgnLi9wbHVnaW5zL3NjaGVtYScpXG5jb25zdCB0eXBlc1BsdWdpbiA9IHJlcXVpcmUoJy4vcGx1Z2lucy90eXBlcycpXG5jb25zdCBvYmpQbHVnaW4gPSByZXF1aXJlKCcuL3BsdWdpbnMvb2JqJylcbmNvbnN0IGVuY2FzZVBsdWdpbiA9IHJlcXVpcmUoJy4vcGx1Z2lucy9lbmNhc2UnKVxuY29uc3QgZGVjb3JhdGVQbHVnaW4gPSByZXF1aXJlKCcuL3BsdWdpbnMvZGVjb3JhdGUnKVxuY29uc3QgYXV0b0luY3JlbWVudFBsdWdpbiA9IHJlcXVpcmUoJy4vcGx1Z2lucy9hdXRvSW5jcmVtZW50JylcbmNvbnN0IGF1dG9HZXRTZXRQbHVnaW4gPSByZXF1aXJlKCcuL3BsdWdpbnMvYXV0b0dldFNldCcpXG4vLyBjb25zdCB2YWxpZGF0b3JCdWlsZGVyID0gcmVxdWlyZSgnLi9kZXBzL3ZhbGlkYXRvcnMvdmFsaWRhdG9yQnVpbGRlcicpXG4vLyBvYmpcbmNvbnN0IGhhc093blByb3BlcnR5ID0gcmVxdWlyZSgnLi9kZXBzL3V0aWwvaGFzT3duUHJvcGVydHknKVxuY29uc3QgZ2V0RGVzY3JpcHRvciA9IHJlcXVpcmUoJy4vZGVwcy91dGlsL2dldERlc2NyaXB0b3InKVxuY29uc3QgT2JqZWN0RGVmaW5lID0gcmVxdWlyZSgnLi9kZXBzL2RlZmluZScpXG5jb25zdCBPYmplY3RLZXlzID0gcmVxdWlyZSgnLi9kZXBzL3V0aWwva2V5cycpXG5jb25zdCBPYmplY3RBc3NpZ24gPSByZXF1aXJlKCcuL2RlcHMvdXRpbC9hc3NpZ24nKVxuLy8gdXRpbHNcbmNvbnN0IHRvYXJyID0gcmVxdWlyZSgnLi9kZXBzL3RvLWFycicpXG5jb25zdCBhcmd1bWVudG9yID0gcmVxdWlyZSgnLi9kZXBzL2FyZ3VtZW50b3InKVxuY29uc3QgY2FtZWxDYXNlID0gcmVxdWlyZSgnLi9kZXBzL2NhbWVsLWNhc2UnKVxuY29uc3QgbWFya0ZvckdhcmJhZ2VDb2xsZWN0aW9uID0gcmVxdWlyZSgnLi9kZXBzL2djJylcbi8vIGlzXG5jb25zdCBpc09iaiA9IHJlcXVpcmUoJy4vZGVwcy9pcy9vYmonKVxuY29uc3QgaXNBcnJheSA9IHJlcXVpcmUoJy4vZGVwcy9pcy9hcnJheScpXG5jb25zdCBpc1VuZGVmaW5lZCA9IHJlcXVpcmUoJy4vZGVwcy9pcy91bmRlZmluZWQnKVxuY29uc3QgaXNUcnVlID0gcmVxdWlyZSgnLi9kZXBzL2lzL3RydWUnKVxuY29uc3QgaXNGYWxzZSA9IHJlcXVpcmUoJy4vZGVwcy9pcy9mYWxzZScpXG5jb25zdCBpc09ialdpdGhLZXlzID0gcmVxdWlyZSgnLi9kZXBzL2lzL29ialdpdGhLZXlzJylcblxuY29uc3QgREVGQVVMVEVEX0tFWSA9ICdkZWZhdWx0ZWQnXG5jb25zdCBNRVRIT0RfS0VZUyA9IFtcbiAgJ29uSW52YWxpZCcsXG4gICdvblZhbGlkJyxcbiAgJ2luaXRpYWwnLFxuICAnZGVmYXVsdCcsXG4gICd0eXBlJyxcbiAgJ2NhbGxSZXR1cm5zJyxcbiAgJ3RhcmdldCcsXG4gICdvblNldCcsXG4gICdvbkNhbGwnLFxuICAnb25HZXQnLFxuXVxuXG4vLyBjb25zdCBTRVRfS0VZID0gTUVUSE9EX0tFWVNbMF1cblxuZnVuY3Rpb24gZ2V0U2V0RmFjdG9yeShfdGhpcywgbmFtZSwgZGVzYykge1xuICBfdGhpc1tjYW1lbENhc2UoYHNldC0ke25hbWV9YCldID0gZGVzYy5zZXRcbiAgX3RoaXNbY2FtZWxDYXNlKGBnZXQtJHtuYW1lfWApXSA9IGRlc2MuZ2V0XG59XG5cbmZ1bmN0aW9uIGFsaWFzRmFjdG9yeShuYW1lLCBwYXJlbnQsIGFsaWFzZXMpIHtcbiAgaWYgKCFpc1VuZGVmaW5lZChhbGlhc2VzKSkge1xuICAgIGZvciAobGV0IGEgPSAwOyBhIDwgYWxpYXNlcy5sZW5ndGg7IGErKykge1xuICAgICAgT2JqZWN0RGVmaW5lKHBhcmVudCwgYWxpYXNlc1thXSwgZ2V0RGVzY3JpcHRvcihwYXJlbnQsIG5hbWUpKVxuICAgIH1cbiAgfVxufVxuXG4vLyBAVE9ETzogdG8gdXNlIGFzIGEgZnVuY3Rpb25cbi8vIGZ1bmN0aW9uIF9tZXRob2RzKCkge31cbi8vIF9tZXRob2RzLnVzZShvYmopIHtcbi8vICAgdGhpcy5vYmogPSBvYmpcbi8vICAgcmV0dXJuIF9tZXRob2RzXG4vLyB9XG4vLyBfbWV0aG9kcy5leHRlbmQgPSBfbWV0aG9kcy51c2Vcbi8vIF9tZXRob2RzLm1ldGhvZHMgPSBmdW5jdGlvbihtZXRob2RzKSB7XG4vLyAgIHJldHVybiBuZXcgTWV0aG9kQ2hhaW4odGhpcy5vYmopXG4vLyB9XG5cbmxldCBtZXRob2RGYWN0b3JpZXNcblxuLyoqXG4gKiBAbWVtYmVyIE1ldGhvZENoYWluXG4gKiBAaW5oZXJpdGRvY1xuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyB7Q2hhaW5lZE1hcH1cbiAqIEB0eXBlIHtNYXB9XG4gKlxuICogQHNpbmNlIDQuMC4wXG4gKlxuICogQFRPRE8gbWF5YmUgYWJzdHJhY3QgdGhlIG1vc3QgcmUtdXNhYmxlIGNvcmUgYXMgYSBwcm90ZWN0ZWQgY2xhc3NcbiAqICAgICAgICBzbyB0aGUgc2hvcnRoYW5kcyBjb3VsZCBiZSB1c2VkLCBhbmQgbW9yZSBmdW5jdGlvbmFsaXR5IG1hZGUgZXh0ZXJuYWxcbiAqIEBUT0RPIG5lZWQgdG8gc2VwYXJhdGUgc2NoZW1hIGZyb20gaGVyZSBhcyBleHRlcm5hbCBmdW5jdGlvbmFsaXR5ICYgYWRkIC5hZGRcbiAqIEBUT0RPIC5wcm9wIC0gZm9yIHRoaW5ncyBvbiB0aGUgaW5zdGFuY2UsIG5vdCBpbiB0aGUgc3RvcmU/XG4gKiAgICAgICAgISEhIC5zcG9uZ2UgLSBhYnNvcm4gcHJvcGVydGllcyBpbnRvIHRoZSBzdG9yZVxuICovXG5jbGFzcyBNZXRob2RDaGFpbiBleHRlbmRzIENoYWluZWRNYXAge1xuICBjb25zdHJ1Y3RvcihwYXJlbnQpIHtcbiAgICAvLyB0aW1lci5zdGFydCgnbWV0aG9kY2hhaW4nKVxuXG4gICAgc3VwZXIocGFyZW50KVxuXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLVxuICAgIGNvbnN0IHNldCA9IHRoaXMuc2V0LmJpbmQodGhpcylcblxuICAgIHRoaXMubmV3VGhpcyA9ICgpID0+IG5ldyBNZXRob2RDaGFpbihwYXJlbnQpXG4gICAgdGhpcy50b051bWJlciA9ICgpID0+IHRoaXMuYnVpbGQoMClcbiAgICB0aGlzLmV4dGVuZChNRVRIT0RfS0VZUylcblxuICAgIC8vIHNob3J0aGFuZFxuICAgIHRoaXMubWV0aG9kID0gdGhpcy5tZXRob2RzID0gbmFtZSA9PiB7XG4gICAgICBpZiAoIXRoaXMubGVuZ3RoKSByZXR1cm4gdGhpcy5uYW1lKG5hbWUpXG4gICAgICByZXR1cm4gdGhpcy5idWlsZCgpLm1ldGhvZHMobmFtZSlcbiAgICB9XG5cbiAgICAvLyBkZWZhdWx0IGFyZ3VtZW50Li4uXG4gICAgdGhpcy5lbmNhc2UgPSB4ID0+IHtcbiAgICAgIHJldHVybiBzZXQoJ2VuY2FzZScsIHBhcmVudFt4XSB8fCB4IHx8IHRydWUpXG4gICAgfVxuXG4gICAgLy8gYWxpYXNcbiAgICB0aGlzLnRoZW4gPSB0aGlzLm9uVmFsaWQuYmluZCh0aGlzKVxuICAgIHRoaXMuY2F0Y2ggPSB0aGlzLm9uSW52YWxpZC5iaW5kKHRoaXMpXG5cbiAgICB0aGlzLnJldHVybnMgPSAoeCwgY2FsbFJldHVybnMpID0+XG4gICAgICBzZXQoJ3JldHVybnMnLCB4IHx8IHBhcmVudCkuY2FsbFJldHVybnMoY2FsbFJldHVybnMpXG5cbiAgICAvLyBATk9URSByZXBsYWNlcyBzaG9ydGhhbmRzLmNoYWluV3JhcFxuICAgIHRoaXMuY2hhaW5hYmxlID0gdGhpcy5yZXR1cm5zXG5cbiAgICAvKipcbiAgICAgKiBAZGVzYyBhbGlhcyBtZXRob2RzXG4gICAgICogQHNpbmNlIDIuMC4wXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtzdHJpbmcgfCBBcnJheTxzdHJpbmc+fSBhbGlhc2VzIGFsaWFzZXMgdG8gcmVtYXAgdG8gdGhlIGN1cnJlbnQgbWV0aG9kIGJlaW5nIGJ1aWx0XG4gICAgICogQHJldHVybiB7TWV0aG9kQ2hhaW59IEBjaGFpbmFibGVcbiAgICAgKlxuICAgICAqIEBOT1RFIHRoZXNlIHdvdWxkIGJlIC50cmFuc2Zvcm1cbiAgICAgKlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiAgICAgY29uc3QgY2hhaW4gPSBuZXcgQ2hhaW4oKVxuICAgICAqICAgICBjaGFpbi5tZXRob2RzKFsnY2FuYWRhJ10pLmFsaWFzKFsnZWgnXSkuYnVpbGQoKVxuICAgICAqICAgICBjaGFpbi5laCgnYWN0dWFsbHkuLi5jYW5hZGEgby5vJylcbiAgICAgKiAgICAgY2hhaW4uZ2V0KCdjYW5hZGEnKVxuICAgICAqICAgICAvLz0+ICdhY3R1YWxseS4uLmNhbmFkYSBvLm8nKVxuICAgICAqXG4gICAgICovXG4gICAgdGhpcy5hbGlhcyA9IGFsaWFzZXMgPT5cbiAgICAgIHRoaXMudGFwKCdhbGlhcycsIChvbGQsIG1lcmdlKSA9PiBtZXJnZShvbGQsIHRvYXJyKGFsaWFzZXMpKSlcbiAgICB0aGlzLnBsdWdpbiA9IHBsdWdpbiA9PlxuICAgICAgdGhpcy50YXAoJ3BsdWdpbnMnLCAob2xkLCBtZXJnZSkgPT4gbWVyZ2Uob2xkLCB0b2FycihwbHVnaW4pKSlcblxuICAgIHRoaXMuY2FtZWxDYXNlID0gKCkgPT4gc2V0KCdjYW1lbCcsIHRydWUpXG5cbiAgICAvLyBATk9URTogeCA9IHRydWUgaXMgbXVjaCBwcmV0dGllciwgYnV0IGNvbXBpbGVzIGJhZGx5XG4gICAgY29uc3QgZGVmYXVsdFRvVHJ1ZSA9IHggPT4gKGlzVW5kZWZpbmVkKHgpID8gdHJ1ZSA6IHgpXG4gICAgdGhpcy5kZWZpbmUgPSB4ID0+IHNldCgnZGVmaW5lJywgZGVmYXVsdFRvVHJ1ZSh4KSlcbiAgICB0aGlzLmdldFNldCA9IHggPT4gc2V0KCdnZXRTZXQnLCBkZWZhdWx0VG9UcnVlKHgpKVxuICAgIC8vIEBUT0RPOiB1bmxlc3MgdGhlc2UgdXNlIHNjb3BlZCB2YXJzLCB0aGV5IHNob3VsZCBiZSBvbiBwcm90b1xuICAgIC8vIEBOT1RFIHNob3J0aGFuZHMuYmluZE1ldGhvZHNcbiAgICB0aGlzLmJpbmQgPSB0YXJnZXQgPT4gc2V0KCdiaW5kJywgaXNVbmRlZmluZWQodGFyZ2V0KSA/IHBhcmVudCA6IHRhcmdldClcbiAgICB0aGlzLmF1dG9HZXRTZXQgPSAoKSA9PiB0aGlzLnBsdWdpbihhdXRvR2V0U2V0UGx1Z2luKVxuXG4gICAgdGhpcy5wbHVnaW4odHlwZXNQbHVnaW4pXG5cbiAgICBpZiAoaXNPYmpXaXRoS2V5cyhtZXRob2RGYWN0b3JpZXMpKSB7XG4gICAgICBPYmplY3RLZXlzKG1ldGhvZEZhY3RvcmllcykuZm9yRWFjaChmYWN0b3J5TmFtZSA9PiB7XG4gICAgICAgIHRoaXNbZmFjdG9yeU5hbWVdID0gYXJnID0+IG1ldGhvZEZhY3Rvcmllc1tmYWN0b3J5TmFtZV0uY2FsbCh0aGlzLCBhcmcpXG4gICAgICAgIGlmIChFTlZfREVWRUxPUE1FTlQpIHtcbiAgICAgICAgICB0aGlzW2ZhY3RvcnlOYW1lXS5tZXRob2RGYWN0b3J5ID0gdHJ1ZVxuICAgICAgICB9XG4gICAgICB9KVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzYyBzZXR1cCBtZXRob2RzIHRvIGJ1aWxkXG4gICAqIEBjYXRlZ29yeSBidWlsZGVyXG4gICAqIEBtZW1iZXJPZiBNZXRob2RDaGFpblxuICAgKlxuICAgKiBAc2luY2UgNC4wLjAtYmV0YS4xIDwtIG1vdmVkIHRvIHBsdWdpblxuICAgKiBAc2luY2UgNC4wLjBcbiAgICpcbiAgICogQHBhcmFtICB7c3RyaW5nIHwgT2JqZWN0IHwgQXJyYXk8c3RyaW5nPn0gbWV0aG9kcyBtZXRob2QgbmFtZXMgdG8gYnVpbGRcbiAgICogQHJldHVybiB7TWV0aG9kQ2hhaW59IEBjaGFpbmFibGVcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgdmFyIG9iaiA9IHt9XG4gICAqICAgIG5ldyBNZXRob2RDaGFpbihvYmopLm5hbWUoJ2VoJykuYnVpbGQoKVxuICAgKiAgICB0eXBlb2Ygb2JqLmVoXG4gICAqICAgIC8vPT4gJ2Z1bmN0aW9uJ1xuICAgKlxuICAgKi9cbiAgbmFtZShtZXRob2RzKSB7XG4gICAgbGV0IG5hbWVzID0gbWV0aG9kc1xuXG4gICAgLyoqXG4gICAgICogQGRlc2MgdGhpcyBpcyBhIHBsdWdpbiBmb3IgYnVpbGRpbmcgbWV0aG9kc1xuICAgICAqICAgICAgIHNjaGVtYSBkZWZhdWx0cyB2YWx1ZSB0byBgLnR5cGVgXG4gICAgICogICAgICAgdGhpcyBkZWZhdWx0cyB2YWx1ZXMgdG8gYC5vbkNhbGxgXG4gICAgICovXG4gICAgaWYgKCFpc0FycmF5KG1ldGhvZHMpICYmIGlzT2JqKG1ldGhvZHMpKSB7XG4gICAgICBuYW1lcyA9IE9iamVjdEtleXMobWV0aG9kcylcbiAgICAgIGZvciAobGV0IG5hbWUgPSAwOyBuYW1lIDwgbmFtZXMubGVuZ3RoOyBuYW1lKyspIHtcbiAgICAgICAgdGhpcy5wbHVnaW4ob2JqUGx1Z2luLmNhbGwodGhpcywgbWV0aG9kcywgbmFtZXNbbmFtZV0pKVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5zZXQoJ25hbWVzJywgbmFtZXMpXG4gIH1cblxuICAvKipcbiAgICogQHNpbmNlIDQuMC4wLWJldGEuMSA8LSBtb3ZlZCB0byBwbHVnaW5cbiAgICogQHNpbmNlIDQuMC4wXG4gICAqXG4gICAqIEBjYXRlZ29yeSB0eXBlc1xuICAgKiBAbWVtYmVyT2YgTWV0aG9kQ2hhaW5cbiAgICpcbiAgICogQHBhcmFtIHtPYmplY3R9IG9iaiBzY2hlbWFcbiAgICogQHJldHVybiB7TWV0aG9kQ2hhaW59IEBjaGFpbmFibGVcbiAgICpcbiAgICogQFRPRE8gbW92ZSBvdXQgaW50byBhIHBsdWdpbiB0byBzaG93IGhvdyBlYXN5IGl0IGlzIHRvIHVzZSBhIHBsdWdpblxuICAgKiAgICAgICBhbmQgbWFrZSBpdCBhYmxlIHRvIGJlIHNwbGl0IG91dCBmb3Igc2l6ZSB3aGVuIG5lZWRlZFxuICAgKlxuICAgKiBAVE9ETyBpbmhlcml0IHByb3BlcnRpZXMgKGluIHBsdWdpbiwgZm9yIGVhY2gga2V5KVxuICAgKiAgICAgICBmcm9tIHRoaXMgZm9yIHNheSwgZG90UHJvcCwgZ2V0U2V0XG4gICAqXG4gICAqIEBUT0RPIHZlcnkgQGltcG9ydGFudFxuICAgKiAgICAgICB0aGF0IHdlIHNldHVwIHNjaGVtYSB2YWxpZGF0aW9uIGF0IHRoZSBoaWdoZXN0IHJvb3QgZm9yIHZhbGlkYXRpb25cbiAgICogICAgICAgYW5kIHRoZW4gaGF2ZSBzb21lIGRlbW8gZm9yIGhvdyB0byB2YWxpZGF0ZSBvbiBzZXQgdXNpbmcgc2F5IG1vYnhcbiAgICogICAgICAgb2JzZXJ2YWJsZXMgZm9yIGFsbCB0aGUgd2F5IGRvd24uLi5cbiAgICovXG4gIHNjaGVtYShvYmopIHtcbiAgICByZXR1cm4gc2NoZW1hTWV0aG9kLmNhbGwodGhpcywgb2JqKVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjIHNldCB0aGUgYWN0dWFsIG1ldGhvZCwgYWxzbyBuZWVkIC5jb250ZXh0IC0gdXNlIC5wYXJlbnRcbiAgICogQG1lbWJlck9mIE1ldGhvZENoYWluXG4gICAqIEBzaW5jZSA0LjAuMFxuICAgKlxuICAgKiBAcGFyYW0gIHthbnl9IFtyZXR1cm5WYWx1ZT11bmRlZmluZWRdIHJldHVybmVkIGF0IHRoZSBlbmQgb2YgdGhlIGZ1bmN0aW9uIGZvciBlYXNlIG9mIHVzZVxuICAgKiBAcmV0dXJuIHtNZXRob2RDaGFpbn0gQGNoYWluYWJsZVxuICAgKlxuICAgKiBAVE9ETyBpZiBwYXNzaW5nIGluIGEgbmFtZSB0aGF0IGFscmVhZHkgZXhpc3RzLCBvcGVyYXRpb25zIGFyZSBkZWNvcmF0aW9ucy4uLiAocGFydGlhbGx5IGRvbmUpXG4gICAqIEBzZWUgaHR0cHM6Ly9naXRodWIuY29tL2lsdXdhdGFyL2phdmEtZGVzaWduLXBhdHRlcm5zL3RyZWUvbWFzdGVyL3N0ZXAtYnVpbGRlclxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiAgICB2YXIgb2JqID0ge31cbiAgICogICAgY29uc3Qgb25lID0gbmV3IE1ldGhvZENoYWluKG9iaikubWV0aG9kcygnZWgnKS5nZXRTZXQoKS5idWlsZCgxKVxuICAgKiAgICAvLz0+IDFcbiAgICpcbiAgICogICAgdHlwZW9mIG9iai5nZXRFaFxuICAgKiAgICAvLz0+ICdmdW5jdGlvbidcbiAgICovXG4gIGJ1aWxkKHJldHVyblZhbHVlKSB7XG4gICAgY29uc3QgcGFyZW50ID0gdGhpcy5wYXJlbnRcbiAgICBjb25zdCBuYW1lcyA9IHRvYXJyKHRoaXMuZ2V0KCduYW1lcycpKVxuICAgIGNvbnN0IHNob3VsZFRhcE5hbWUgPSB0aGlzLmdldCgnY2FtZWwnKVxuXG4gICAgZm9yIChsZXQgbmFtZSA9IDA7IG5hbWUgPCBuYW1lcy5sZW5ndGg7IG5hbWUrKykge1xuICAgICAgdGhpcy5fYnVpbGQoc2hvdWxkVGFwTmFtZSA/IGNhbWVsQ2FzZShuYW1lc1tuYW1lXSkgOiBuYW1lc1tuYW1lXSwgcGFyZW50KVxuICAgIH1cblxuICAgIC8vIHRpbWVyLnN0b3AoJ21ldGhvZGNoYWluJykubG9nKCdtZXRob2RjaGFpbicpLnN0YXJ0KCdnYycpXG5cbiAgICAvLyByZW1vdmUgcmVmcyB0byB1bnVzZWRcbiAgICB0aGlzLmNsZWFyKClcbiAgICBkZWxldGUgdGhpcy5wYXJlbnRcbiAgICBtYXJrRm9yR2FyYmFnZUNvbGxlY3Rpb24odGhpcylcblxuICAgIC8vIHZlcnkgZmFzdCAtIHRpbWVyICYgZW5zdXJpbmcgcHJvcHMgYXJlIGNsZWFuZWRcbiAgICAvLyB0aW1lci5zdG9wKCdnYycpLmxvZygnZ2MnKVxuICAgIC8vIHJlcXVpcmUoJ2ZsaXBsb2cnKS5xdWljayh0aGlzKVxuXG4gICAgcmV0dXJuIGlzVW5kZWZpbmVkKHJldHVyblZhbHVlKSA/IHBhcmVudCA6IHJldHVyblZhbHVlXG4gIH1cblxuICAvKipcbiAgICogQG1lbWJlck9mIE1ldGhvZENoYWluXG4gICAqXG4gICAqIEBzaW5jZSA0LjAuMFxuICAgKiBAcHJvdGVjdGVkXG4gICAqIEBwYXJhbSB7UHJpbWl0aXZlfSBuYW1lIG1ldGhvZCBuYW1lXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBwYXJlbnQgYmVpbmcgZGVjb3JhdGVkXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBidWlsdCBtZXRob2QgYmVpbmcgYnVpbHRcbiAgICogQHJldHVybiB7dm9pZH1cbiAgICpcbiAgICogQFRPRE8gb3B0aW1pemUgdGhlIHNpemUgb2YgdGhpc1xuICAgKiAgICAgICAgd2l0aCBzb21lIGJpdHdpc2Ugb3BlcmF0b3JzXG4gICAqICAgICAgICBoYXNoaW5nIHRoZSB0aGluZ3MgdGhhdCBoYXZlIGJlZW4gZGVmYXVsdGVkXG4gICAqICAgICAgICBhbHNvIGNvdWxkIGJlIHBsdWdpblxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiAgLl9kZWZhdWx0cygnJywge30sIHt9KVxuICAgKi9cbiAgX2RlZmF1bHRzKG5hbWUsIHBhcmVudCwgYnVpbHQpIHtcbiAgICAvLyBkZWZhdWx0c1xuICAgIGNvbnN0IGRlZmF1bHRPblNldCA9IGFyZyA9PiBwYXJlbnQuc2V0KG5hbWUsIGFyZylcbiAgICBjb25zdCBkZWZhdWx0T25HZXQgPSAoKSA9PiBwYXJlbnQuZ2V0KG5hbWUpXG5cbiAgICAvLyBzbyB3ZSBrbm93IGlmIHdlIGRlZmF1bHRlZCB0aGVtXG4gICAgZGVmYXVsdE9uU2V0W0RFRkFVTFRFRF9LRVldID0gdHJ1ZVxuICAgIGRlZmF1bHRPbkdldFtERUZBVUxURURfS0VZXSA9IHRydWVcblxuICAgIC8vIHdoZW4gd2UndmVbREVGQVVMVEVEX0tFWV0gYWxyZWFkeSBmb3IgYW5vdGhlciBtZXRob2QsXG4gICAgLy8gd2UgbmVlZCBhIG5ldyBmdW5jdGlvbixcbiAgICAvLyBlbHNlIHRoZSBuYW1lIHdpbGwgYmUgc2NvcGVkIGluY29ycmVjdGx5XG4gICAgY29uc3Qge29uQ2FsbCwgb25TZXQsIG9uR2V0fSA9IGJ1aWx0XG4gICAgaWYgKCFvbkdldCB8fCBvbkdldFtERUZBVUxURURfS0VZXSkge1xuICAgICAgdGhpcy5vbkdldChkZWZhdWx0T25HZXQpXG4gICAgfVxuICAgIGlmICghb25DYWxsIHx8IG9uQ2FsbFtERUZBVUxURURfS0VZXSkge1xuICAgICAgdGhpcy5vbkNhbGwoZGVmYXVsdE9uU2V0KVxuICAgIH1cbiAgICBpZiAoIW9uU2V0IHx8IG9uU2V0W0RFRkFVTFRFRF9LRVldKSB7XG4gICAgICB0aGlzLm9uU2V0KGRlZmF1bHRPblNldClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQHByb3RlY3RlZFxuICAgKiBAc2luY2UgNC4wLjAtYWxwaGEuMVxuICAgKiBAbWVtYmVyT2YgTWV0aG9kQ2hhaW5cbiAgICpcbiAgICogQHBhcmFtIHtQcmltaXRpdmV9IG5hbWVcbiAgICogQHBhcmFtIHtPYmplY3R9IHBhcmVudFxuICAgKiBAcmV0dXJuIHt2b2lkfVxuICAgKlxuICAgKiBAVE9ETyBhbGxvdyBjb25maWcgb2YgbWV0aG9kIHZhciBpbiBwbHVnaW5zIHNpbmNlIGl0IGlzIHNjb3BlZC4uLlxuICAgKiBAVE9ETyBhZGQgdG8gLm1ldGEoc2hvcnRoYW5kcylcbiAgICogQFRPRE8gcmVkdWNlIGNvbXBsZXhpdHkgaWYgcGVyZiBhbGxvd3NcbiAgICogQE5PVEUgc2NvcGluZyBoZXJlIGFkZGluZyBkZWZhdWx0IGZ1bmN0aW9ucyBoYXZlIHRvIHJlc2NvcGUgYXJndW1lbnRzXG4gICAqL1xuICBfYnVpbGQobmFtZSwgcGFyZW50KSB7XG4gICAgbGV0IG1ldGhvZFxuICAgIGxldCBleGlzdGluZ1xuICAgIGNvbnN0IGVudHJpZXMgPSAoKSA9PiB0aGlzLmVudHJpZXMoKVxuXG4gICAgLy8gY291bGQgdGVybmFyeSBgbGV0IG1ldGhvZCA9YCBoZXJlXG4gICAgaWYgKGhhc093blByb3BlcnR5KHBhcmVudCwgbmFtZSkpIHtcbiAgICAgIGV4aXN0aW5nID0gZ2V0RGVzY3JpcHRvcihwYXJlbnQsIG5hbWUpXG5cbiAgICAgIC8vIGF2b2lkIGBUeXBlRXJyb3I6IENhbm5vdCByZWRlZmluZSBwcm9wZXJ0eTpgXG4gICAgICBpZiAoaXNGYWxzZShleGlzdGluZy5jb25maWd1cmFibGUpKSB7XG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICAvLyB1c2UgZXhpc3RpbmcgcHJvcGVydHksIHdoZW4gY29uZmlndXJhYmxlXG4gICAgICBtZXRob2QgPSBleGlzdGluZy52YWx1ZVxuXG4gICAgICBpZiAoRU5WX0RFVkVMT1BNRU5UKSB7XG4gICAgICAgIG1ldGhvZC5kZWNvcmF0ZWQgPSB0cnVlXG4gICAgICB9XG5cbiAgICAgIHRoaXMub25DYWxsKG1ldGhvZCkub25TZXQobWV0aG9kKVxuICAgIH1cbiAgICBlbHNlIGlmIChwYXJlbnRbbmFtZV0pIHtcbiAgICAgIG1ldGhvZCA9IHBhcmVudFtuYW1lXVxuXG4gICAgICBpZiAoRU5WX0RFVkVMT1BNRU5UKSB7XG4gICAgICAgIG1ldGhvZC5kZWNvcmF0ZWQgPSB0cnVlXG4gICAgICB9XG5cbiAgICAgIHRoaXMub25DYWxsKG1ldGhvZCkub25TZXQobWV0aG9kKVxuICAgIH1cblxuICAgIC8vIHNjb3BlIGl0IG9uY2UgZm9yIHBsdWdpbnMgJiB0eXBlIGJ1aWxkaW5nLCB0aGVuIGdldCBpdCBhZ2FpblxuICAgIGxldCBidWlsdCA9IGVudHJpZXMoKVxuXG4gICAgdGhpcy5fZGVmYXVsdHMobmFtZSwgcGFyZW50LCBidWlsdClcblxuICAgIC8vIHBsdWdpbnMgY2FuIGFkZCBtZXRob2RzLFxuICAgIC8vIHVzZWZ1bCBhcyBwbHVnaW5zL3ByZXNldHMgJiBkZWNvcmF0b3JzIGZvciBtdWx0aS1uYW1lIGJ1aWxkaW5nXG4gICAgY29uc3QgaW5zdGFuY2VQbHVnaW5zID0gYnVpbHQucGx1Z2luc1xuICAgIGlmIChpbnN0YW5jZVBsdWdpbnMpIHtcbiAgICAgIGZvciAobGV0IHBsdWdpbiA9IDA7IHBsdWdpbiA8IGluc3RhbmNlUGx1Z2lucy5sZW5ndGg7IHBsdWdpbisrKSB7XG4gICAgICAgIGJ1aWx0ID0gZW50cmllcygpXG4gICAgICAgIGluc3RhbmNlUGx1Z2luc1twbHVnaW5dLmNhbGwodGhpcywgbmFtZSwgcGFyZW50LCBidWlsdClcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBhZnRlciBsYXN0IHBsdWdpbiBpcyBmaW5pc2hlZCwgb3IgZGVmYXVsdHNcbiAgICBidWlsdCA9IGVudHJpZXMoKVxuXG4gICAgLy8gd3JhcCBpbiBlbmNhc2luZyB3aGVuIHdlIGhhdmUgYSB2YWxpZGF0b3Igb3IgLmVuY2FzZVxuICAgIC8vIEBOT1RFOiB2YWxpZGF0b3IgcGx1Z2luIHdhcyBoZXJlLCBtb3ZlZCBpbnRvIGEgcGx1Z2luXG4gICAgaWYgKGJ1aWx0LmVuY2FzZSkge1xuICAgICAgY29uc3QgZW5jYXNlZCA9IGVuY2FzZVBsdWdpbi5jYWxsKHRoaXMsIG5hbWUsIHBhcmVudCwgYnVpbHQpKG1ldGhvZClcblxuICAgICAgaWYgKEVOVl9ERVZFTE9QTUVOVCkge1xuICAgICAgICBlbmNhc2VkLmVuY2FzZWQgPSBtZXRob2RcbiAgICAgIH1cblxuICAgICAgdGhpcy5vbkNhbGwoZW5jYXNlZCkub25TZXQoZW5jYXNlZClcbiAgICAgIG1ldGhvZCA9IGVuY2FzZWRcbiAgICAgIGJ1aWx0ID0gZW50cmllcygpXG4gICAgfVxuXG4gICAgLy8gbm90IGRlc3RydWN0dXJlZCBmb3IgYmV0dGVyIHZhcmlhYmxlIG5hbWVzXG4gICAgY29uc3Qgc2hvdWxkQWRkR2V0dGVyU2V0dGVyID0gYnVpbHQuZ2V0U2V0XG4gICAgY29uc3Qgc2hvdWxkRGVmaW5lR2V0U2V0ID0gYnVpbHQuZGVmaW5lXG4gICAgY29uc3QgZGVmYXVsdFZhbHVlID0gYnVpbHQuZGVmYXVsdFxuXG4gICAgLy8gY2FuIG9ubHkgaGF2ZSBgY2FsbGAgb3IgYGdldC9zZXRgLi4uXG4gICAgY29uc3Qge1xuICAgICAgb25HZXQsXG4gICAgICBvblNldCxcbiAgICAgIG9uQ2FsbCxcbiAgICAgIGluaXRpYWwsXG4gICAgICBiaW5kLFxuICAgICAgcmV0dXJucyxcbiAgICAgIGNhbGxSZXR1cm5zLFxuICAgICAgYWxpYXMsXG4gICAgfSA9IGJ1aWx0XG5cbiAgICAvLyBkZWZhdWx0IG1ldGhvZCwgaWYgd2UgZG8gbm90IGhhdmUgb25lIGFscmVhZHlcbiAgICBpZiAoIW1ldGhvZCkge1xuICAgICAgbWV0aG9kID0gKGFyZyA9IGRlZmF1bHRWYWx1ZSkgPT4gb25DYWxsLmNhbGwocGFyZW50LCBhcmcpXG5cbiAgICAgIGlmIChFTlZfREVWRUxPUE1FTlQpIHtcbiAgICAgICAgbWV0aG9kLmNyZWF0ZWQgPSB0cnVlXG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGJpbmQpIHtcbiAgICAgIC8vIGJpbmQgPSBiaW5kQXJndW1lbnQgfHwgcGFyZW50XG4gICAgICBtZXRob2QgPSBtZXRob2QuYmluZChiaW5kKVxuICAgIH1cbiAgICBpZiAocmV0dXJucykge1xuICAgICAgY29uc3QgcmVmID0gbWV0aG9kXG4gICAgICBtZXRob2QgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgY29uc3QgYXJncyA9IGFyZ3VtZW50b3IuYXBwbHkobnVsbCwgYXJndW1lbnRzKVxuXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBwcmVmZXItcmVzdC1wYXJhbXNcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gcmVmLmFwcGx5KHBhcmVudCwgYXJncylcblxuICAgICAgICByZXR1cm4gaXNUcnVlKGNhbGxSZXR1cm5zKVxuICAgICAgICAgID8gcmV0dXJucy5hcHBseShwYXJlbnQsIFtyZXN1bHRdLmNvbmNhdChhcmdzKSlcbiAgICAgICAgICA6IHJldHVybnNcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoIWlzVW5kZWZpbmVkKGluaXRpYWwpKSB7XG4gICAgICBwYXJlbnQuc2V0KG5hbWUsIGluaXRpYWwpXG4gICAgfVxuXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tIHN0cmlwcGVkIC0tLS0tLS0tLS0tXG5cbiAgICAvKipcbiAgICAgKiAhISEhISBAVE9ETzogcHV0IGluIGBwbHVnaW5zLnBvc3QuY2FsbGBcbiAgICAgKiAhISEhISBAVE9ETzogZW5zdXJlIHVuaXF1ZSBuYW1lXG4gICAgICpcbiAgICAgKiBjYW4gYWRkIC5tZXRhIG9uIHRoZW0gdGhvdWdoIGZvciByZS1kZWNvcmF0aW5nXG4gICAgICogLT4gYnV0IHRoaXMgaGFzIGlzc3VlIHdpdGggLmdldHNldCBzbyBuZWVkcyB0byBiZSBvbiAubWV0YVtuYW1lXVxuICAgICAqL1xuXG4gICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQ6IGRldiAqL1xuICAgIGlmIChFTlZfREVWRUxPUE1FTlQpIHtcbiAgICAgIE9iamVjdERlZmluZShvbkdldCwgJ25hbWUnLCB7XG4gICAgICAgIHZhbHVlOiBjYW1lbENhc2UoYCR7b25HZXQubmFtZX0rZ2V0LSR7bmFtZX1gKSxcbiAgICAgIH0pXG4gICAgICBPYmplY3REZWZpbmUob25TZXQsICduYW1lJywge1xuICAgICAgICB2YWx1ZTogY2FtZWxDYXNlKGAke29uU2V0Lm5hbWV9K3NldC0ke25hbWV9YCksXG4gICAgICB9KVxuICAgICAgT2JqZWN0RGVmaW5lKG9uQ2FsbCwgJ25hbWUnLCB7XG4gICAgICAgIHZhbHVlOiBjYW1lbENhc2UoYCR7b25DYWxsLm5hbWV9K2NhbGwtJHtuYW1lfWApLFxuICAgICAgfSlcbiAgICAgIE9iamVjdERlZmluZShtZXRob2QsICduYW1lJywge3ZhbHVlOiBjYW1lbENhc2UoYCR7bmFtZX1gKX0pXG5cbiAgICAgIGlmIChidWlsdC50eXBlKSBtZXRob2QudHlwZSA9IGJ1aWx0LnR5cGVcbiAgICAgIGlmIChpbml0aWFsKSBtZXRob2QuaW5pdGlhbCA9IGluaXRpYWxcbiAgICAgIGlmIChiaW5kKSBtZXRob2QuYm91bmQgPSBiaW5kXG4gICAgICBpZiAocmV0dXJucykgbWV0aG9kLnJldHVybnMgPSByZXR1cm5zXG4gICAgICBpZiAoYWxpYXMpIG1ldGhvZC5hbGlhcyA9IGFsaWFzXG4gICAgICBpZiAoY2FsbFJldHVybnMpIG1ldGhvZC5jYWxsUmV0dXJucyA9IGNhbGxSZXR1cm5zXG4gICAgICBpZiAob25HZXQpIG1ldGhvZC5fZ2V0ID0gb25HZXRcbiAgICAgIGlmIChvblNldCkgbWV0aG9kLl9zZXQgPSBvblNldFxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG4gICAgICBpZiAob25DYWxsICE9IG9uQ2FsbCkgbWV0aG9kLl9jYWxsID0gb25DYWxsXG4gICAgfVxuXG4gICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQ6IGRldiAqL1xuICAgIGlmIChFTlZfREVCVUcpIHtcbiAgICAgIGNvbnNvbGUubG9nKHtcbiAgICAgICAgbmFtZSxcbiAgICAgICAgZGVmYXVsdFZhbHVlLFxuICAgICAgICBpbml0aWFsLFxuICAgICAgICByZXR1cm5zLFxuICAgICAgICBvbkdldCxcbiAgICAgICAgb25TZXQsXG4gICAgICAgIG1ldGhvZDogbWV0aG9kLnRvU3RyaW5nKCksXG4gICAgICB9KVxuICAgIH1cblxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tIDtzdHJpcHBlZCAtLS0tLS0tLS0tLS1cblxuICAgIC8vIEBUT0RPOiBXT1VMRCBBTEwgQkUgTUVUSE9ELlBPU1RcbiAgICAvLyAtLS0gY291bGQgYmUgYSBtZXRob2QgdG9vIC0tLVxuICAgIGNvbnN0IGdldHRlclNldHRlciA9IHtnZXQ6IG9uR2V0LCBzZXQ6IG9uU2V0fVxuICAgIGxldCBkZXNjcmlwdG9yID0gc2hvdWxkRGVmaW5lR2V0U2V0ID8gZ2V0dGVyU2V0dGVyIDoge3ZhbHVlOiBtZXRob2R9XG4gICAgaWYgKGV4aXN0aW5nKSBkZXNjcmlwdG9yID0gT2JqZWN0QXNzaWduKGV4aXN0aW5nLCBkZXNjcmlwdG9yKVxuXG4gICAgLy8gW1R5cGVFcnJvcjogSW52YWxpZCBwcm9wZXJ0eSBkZXNjcmlwdG9yLlxuICAgIC8vIENhbm5vdCBib3RoIHNwZWNpZnkgYWNjZXNzb3JzIGFuZCBhIHZhbHVlIG9yIHdyaXRhYmxlIGF0dHJpYnV0ZSwgIzxPYmplY3Q+XVxuICAgIGlmIChkZXNjcmlwdG9yLnZhbHVlICYmIGRlc2NyaXB0b3IuZ2V0KSB7XG4gICAgICBkZWxldGUgZGVzY3JpcHRvci52YWx1ZVxuICAgIH1cbiAgICBpZiAoIWlzVW5kZWZpbmVkKGRlc2NyaXB0b3Iud3JpdGFibGUpKSB7XG4gICAgICBkZWxldGUgZGVzY3JpcHRvci53cml0YWJsZVxuICAgIH1cblxuICAgIGNvbnN0IHRhcmdldCA9IHRoaXMuZ2V0KCd0YXJnZXQnKSB8fCBwYXJlbnRcblxuICAgIE9iamVjdERlZmluZSh0YXJnZXQsIG5hbWUsIGRlc2NyaXB0b3IpXG5cbiAgICBpZiAoc2hvdWxkQWRkR2V0dGVyU2V0dGVyKSB7XG4gICAgICBpZiAodGFyZ2V0Lm1ldGEpIHRhcmdldC5tZXRhKFNIT1JUSEFORFNfS0VZLCBuYW1lLCBvblNldClcbiAgICAgIGdldFNldEZhY3RvcnkodGFyZ2V0LCBuYW1lLCBnZXR0ZXJTZXR0ZXIpXG4gICAgfVxuXG4gICAgYWxpYXNGYWN0b3J5KG5hbWUsIHRhcmdldCwgYWxpYXMpXG5cbiAgICAvLyBpZiAoYnVpbHQubWV0YWRhdGEpIHtcbiAgICAvLyAgIHRhcmdldC5tZXRhKFNIT1JUSEFORFNfS0VZLCBuYW1lLCBzZXQpXG4gICAgLy8gfVxuICAgIC8vIHJlcXVpcmUoJ2ZsaXBsb2cnKVxuICAgIC8vICAgLmJvbGQoJ2RlY29yYXRlJylcbiAgICAvLyAgIC5kYXRhKHtcbiAgICAvLyAgICAgLy8gdDogdGhpcyxcbiAgICAvLyAgICAgZGVzY3JpcHRvcixcbiAgICAvLyAgICAgc2hvdWxkRGVmaW5lR2V0U2V0LFxuICAgIC8vICAgICBtZXRob2QsXG4gICAgLy8gICAgIHN0cjogbWV0aG9kLnRvU3RyaW5nKCksXG4gICAgLy8gICAgIC8vIHRhcmdldCxcbiAgICAvLyAgICAgbmFtZSxcbiAgICAvLyAgIH0pXG4gICAgLy8gICAuZWNobygpXG4gIH1cblxuICAvLyAtLS1cblxuICAvKipcbiAgICogQGRlc2MgYWRkIG1ldGhvZHMgdG8gdGhlIHBhcmVudCBmb3IgZWFzaWVyIGNoYWluaW5nXG4gICAqIEBhbGlhcyBleHRlbmRQYXJlbnRcbiAgICogQG1lbWJlck9mIE1ldGhvZENoYWluXG4gICAqXG4gICAqIEBzaW5jZSA0LjAuMC1iZXRhLjEgPC0gbW92ZWQgdG8gcGx1Z2luXG4gICAqIEBzaW5jZSA0LjAuMCA8LSBtb3ZlZCBmcm9tIEV4dGVuZFxuICAgKiBAc2luY2UgMS4wLjBcbiAgICpcbiAgICogQHBhcmFtIHtPYmplY3R9IFtwYXJlbnRUb0RlY29yYXRlPXVuZGVmaW5lZF0gZGVjb3JhdGUgYSBzcGVjaWZpYyBwYXJlbnQgc2hvcnRoYW5kXG4gICAqIEByZXR1cm4ge0NoYWluZWRNYXB9IEBjaGFpbmFibGVcbiAgICpcbiAgICogQHNlZSBwbHVnaW5zL2RlY29yYXRlXG4gICAqIEBzZWUgQ2hhaW5lZE1hcC5wYXJlbnRcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogIHZhciBvYmogPSB7fVxuICAgKiAgbmV3IE1ldGhvZENoYWluKHt9KS5uYW1lKCdlaCcpLmRlY29yYXRlKG9iaikuYnVpbGQoKVxuICAgKiAgdHlwZW9mIG9iai5laFxuICAgKiAgLy89PiAnZnVuY3Rpb24nXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgICBjbGFzcyBEZWNvcmF0b3IgZXh0ZW5kcyBDaGFpbiB7XG4gICAqICAgICAgIGNvbnN0cnVjdG9yKHBhcmVudCkge1xuICAgKiAgICAgICAgIHN1cGVyKHBhcmVudClcbiAgICogICAgICAgICB0aGlzLm1ldGhvZHMoWydlYXN5J10pLmRlY29yYXRlKHBhcmVudCkuYnVpbGQoKVxuICAgKiAgICAgICAgIHRoaXMubWV0aG9kcygnYWR2YW5jZWQnKVxuICAgKiAgICAgICAgICAgLm9uQ2FsbCh0aGlzLmFkdmFuY2VkLmJpbmQodGhpcykpXG4gICAqICAgICAgICAgICAuZGVjb3JhdGUocGFyZW50KVxuICAgKiAgICAgICAgICAgLmJ1aWxkKClcbiAgICogICAgICAgfVxuICAgKiAgICAgICBhZHZhbmNlZChhcmcpIHtcbiAgICogICAgICAgICB0aGlzLnNldCgnYWR2YW5jZWQnLCBhcmcpXG4gICAqICAgICAgICAgcmV0dXJuIHRoaXMucGFyZW50XG4gICAqICAgICAgIH1cbiAgICogICAgICAgZWFzeShhcmcpIHtcbiAgICogICAgICAgICB0aGlzLnBhcmVudC5zZXQoJ2Vhc3ktcGVhc3knLCBhcmcpXG4gICAqICAgICAgIH1cbiAgICogICAgIH1cbiAgICpcbiAgICogICAgIGNsYXNzIE1hc3RlciBleHRlbmRzIENoYWluIHtcbiAgICogICAgICAgY29uc3RydWN0b3IocGFyZW50KSB7XG4gICAqICAgICAgICAgc3VwZXIocGFyZW50KVxuICAgKiAgICAgICAgIHRoaXMuZWggPSBuZXcgRGVjb3JhdG9yKHRoaXMpXG4gICAqICAgICAgIH1cbiAgICogICAgIH1cbiAgICpcbiAgICogICAgIGNvbnN0IG1hc3RlciA9IG5ldyBNYXN0ZXIoKVxuICAgKlxuICAgKiAgICAgbWFzdGVyLmdldCgnZWFzeS1wZWFzeScpXG4gICAqICAgICAvLz0+IHRydWVcbiAgICpcbiAgICogICAgIG1hc3Rlci5laC5nZXQoJ2FkdmFuY2VkJylcbiAgICogICAgIC8vPT4gJ2ErJ1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICArY2hhaW4ubWV0aG9kKCdlaE9oJykuZGVjb3JhdGUobnVsbClcbiAgICogICAgLy89PiBAdGhyb3dzIEVycm9yKCdtdXN0IHByb3ZpZGUgcGFyZW50IGFyZ3VtZW50JylcbiAgICpcbiAgICovXG4gIGRlY29yYXRlKHBhcmVudFRvRGVjb3JhdGUpIHtcbiAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dDogZGV2cyAqL1xuICAgIGlmIChFTlZfREVWRUxPUE1FTlQpIHtcbiAgICAgIGlmICghKHBhcmVudFRvRGVjb3JhdGUgfHwgdGhpcy5wYXJlbnQucGFyZW50KSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ211c3QgcHJvdmlkZSBwYXJlbnQgYXJndW1lbnQnKVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZGVjb3JhdGVQbHVnaW4uY2FsbCh0aGlzLCBwYXJlbnRUb0RlY29yYXRlIHx8IHRoaXMucGFyZW50LnBhcmVudClcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzYyBhZGRzIGEgcGx1Z2luIHRvIGluY3JlbWVudCB0aGUgdmFsdWUgb24gZXZlcnkgY2FsbFxuICAgKiAgICAgICAgQG1vZGlmaWVzIHRoaXMuaW5pdGlhbFxuICAgKiAgICAgICAgQG1vZGlmaWVzIHRoaXMub25DYWxsXG4gICAqXG4gICAqIEBtZW1iZXJPZiBNZXRob2RDaGFpblxuICAgKiBAc2luY2UgNC4wLjAtYmV0YS4xIDwtIG1vdmVkIHRvIHBsdWdpblxuICAgKiBAc2luY2UgNC4wLjAgPC0gcmVuYW1lZCBmcm9tIC5leHRlbmRJbmNyZW1lbnRcbiAgICogQHNpbmNlIDAuNC4wXG4gICAqXG4gICAqIEByZXR1cm4ge01ldGhvZENoYWlufSBAY2hhaW5hYmxlXG4gICAqXG4gICAqIEBzZWUgcGx1Z2lucy9hdXRvSW5jcmVtZW50XG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgICBjaGFpbi5tZXRob2RzKFsnaW5kZXgnXSkuYXV0b0luY3JlbWVudCgpLmJ1aWxkKCkuaW5kZXgoKS5pbmRleCgrMSkuaW5kZXgoKVxuICAgKiAgICAgY2hhaW4uZ2V0KCdpbmRleCcpXG4gICAqICAgICAvLz0+IDNcbiAgICpcbiAgICovXG4gIGF1dG9JbmNyZW1lbnQoKSB7XG4gICAgcmV0dXJuIHRoaXMucGx1Z2luKGF1dG9JbmNyZW1lbnRQbHVnaW4pXG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzYyBhZGQgbWV0aG9kRmFjdG9yaWVzIGVhc2lseVxuICogQHN0YXRpY1xuICogQHNpbmNlIDQuMC4wLWJldGEuMlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBtZXRob2RGYWN0b3J5IGZhY3RvcmllcyB0byBhZGRcbiAqIEByZXR1cm4ge3ZvaWR9XG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiAgIGZ1bmN0aW9uIGF1dG9HZXRTZXQobmFtZSwgcGFyZW50KSB7XG4gKiAgICAgY29uc3QgYXV0byA9IGFyZyA9PlxuICogICAgICAgKGlzVW5kZWZpbmVkKGFyZykgPyBwYXJlbnQuZ2V0KG5hbWUpIDogcGFyZW50LnNldChuYW1lLCBhcmcpKVxuICpcbiAqICAgICAvL3NvIHdlIGtub3cgaWYgd2UgZGVmYXVsdGVkIHRoZW1cbiAqICAgICBhdXRvLmF1dG9HZXRTZXQgPSB0cnVlXG4gKiAgICAgcmV0dXJuIHRoaXMub25TZXQoYXV0bykub25HZXQoYXV0bykub25DYWxsKGF1dG8pXG4gKiAgIH1cbiAqICAgTWV0aG9kQ2hhaW4uYWRkUGx1Z2luKHthdXRvR2V0U2V0fSlcbiAqXG4gKlxuICogICBjb25zdCBjaGFpbiA9IG5ldyBDaGFpbigpXG4gKiAgIGNoYWluLm1ldGhvZHMoJ2VoJykuYXV0b0dldFNldCgpLmJ1aWxkKClcbiAqXG4gKiAgIGNoYWluLmVoKDEpXG4gKiAgIC8vPT4gY2hhaW5cbiAqICAgY2hhaW4uZWgoKVxuICogICAvLz0+IDEgKlxuICpcbiAqL1xuTWV0aG9kQ2hhaW4uYWRkID0gZnVuY3Rpb24gYWRkTWV0aG9kRmFjdG9yaWVzKG1ldGhvZEZhY3RvcnkpIHtcbiAgT2JqZWN0QXNzaWduKG1ldGhvZEZhY3RvcmllcywgbWV0aG9kRmFjdG9yeSlcbn1cbm1ldGhvZEZhY3RvcmllcyA9IE1ldGhvZENoYWluLmFkZFxuXG4vLyBNZXRob2RDaGFpbi5hZGRUeXBlcyA9IHR5cGVzID0+IHtcbi8vICAgdmFsaWRhdG9yQnVpbGRlci5tZXJnZSh0eXBlcylcbi8vICAgcmV0dXJuIE1ldGhvZENoYWluXG4vLyB9XG5cbm1vZHVsZS5leHBvcnRzID0gTWV0aG9kQ2hhaW5cbiJdLCJuYW1lcyI6WyJjb25zdCIsImxldCIsInN1cGVyIiwidGhpcyJdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7QUFnQkFBLEdBQUssQ0FBQyxVQUFVLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixDQUFDO0FBQzlDQSxHQUFLLENBQUMsY0FBYyxHQUFHLE9BQU8sQ0FBQyx3QkFBd0IsQ0FBQztBQUN4REEsR0FBSyxDQUFDLGVBQWUsR0FBRyxPQUFPLENBQUMsZ0JBQWdCLENBQUM7QUFDakRBLEdBQUssQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixDQUFDOztBQUU3Q0EsR0FBSyxDQUFDLFlBQVksR0FBRyxPQUFPLENBQUMsa0JBQWtCLENBQUM7QUFDaERBLEdBQUssQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFDLGlCQUFpQixDQUFDO0FBQzlDQSxHQUFLLENBQUMsU0FBUyxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUM7QUFDMUNBLEdBQUssQ0FBQyxZQUFZLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixDQUFDO0FBQ2hEQSxHQUFLLENBQUMsY0FBYyxHQUFHLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQztBQUNwREEsR0FBSyxDQUFDLG1CQUFtQixHQUFHLE9BQU8sQ0FBQyx5QkFBeUIsQ0FBQztBQUM5REEsR0FBSyxDQUFDLGdCQUFnQixHQUFHLE9BQU8sQ0FBQyxzQkFBc0IsQ0FBQzs7O0FBR3hEQSxHQUFLLENBQUMsY0FBYyxHQUFHLE9BQU8sQ0FBQyw0QkFBNEIsQ0FBQztBQUM1REEsR0FBSyxDQUFDLGFBQWEsR0FBRyxPQUFPLENBQUMsMkJBQTJCLENBQUM7QUFDMURBLEdBQUssQ0FBQyxZQUFZLEdBQUcsT0FBTyxDQUFDLGVBQWUsQ0FBQztBQUM3Q0EsR0FBSyxDQUFDLFVBQVUsR0FBRyxPQUFPLENBQUMsa0JBQWtCLENBQUM7QUFDOUNBLEdBQUssQ0FBQyxZQUFZLEdBQUcsT0FBTyxDQUFDLG9CQUFvQixDQUFDOztBQUVsREEsR0FBSyxDQUFDLEtBQUssR0FBRyxPQUFPLENBQUMsZUFBZSxDQUFDO0FBQ3RDQSxHQUFLLENBQUMsVUFBVSxHQUFHLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQztBQUMvQ0EsR0FBSyxDQUFDLFNBQVMsR0FBRyxPQUFPLENBQUMsbUJBQW1CLENBQUM7QUFDOUNBLEdBQUssQ0FBQyx3QkFBd0IsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDOztBQUVyREEsR0FBSyxDQUFDLEtBQUssR0FBRyxPQUFPLENBQUMsZUFBZSxDQUFDO0FBQ3RDQSxHQUFLLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQztBQUMxQ0EsR0FBSyxDQUFDLFdBQVcsR0FBRyxPQUFPLENBQUMscUJBQXFCLENBQUM7QUFDbERBLEdBQUssQ0FBQyxNQUFNLEdBQUcsT0FBTyxDQUFDLGdCQUFnQixDQUFDO0FBQ3hDQSxHQUFLLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQztBQUMxQ0EsR0FBSyxDQUFDLGFBQWEsR0FBRyxPQUFPLENBQUMsdUJBQXVCLENBQUM7O0FBRXREQSxHQUFLLENBQUMsYUFBYSxHQUFHLFdBQVc7QUFDakNBLEdBQUssQ0FBQyxXQUFXLEdBQUc7RUFDbEIsV0FBVztFQUNYLFNBQVM7RUFDVCxTQUFTO0VBQ1QsU0FBUztFQUNULE1BQU07RUFDTixhQUFhO0VBQ2IsUUFBUTtFQUNSLE9BQU87RUFDUCxRQUFRO0VBQ1IsT0FBTztDQUNSOzs7O0FBSUQsU0FBUyxhQUFhLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUU7RUFDeEMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFBLE1BQUssR0FBRSxJQUFJLENBQUUsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUc7RUFDMUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFBLE1BQUssR0FBRSxJQUFJLENBQUUsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUc7Q0FDM0M7O0FBRUQsU0FBUyxZQUFZLENBQUMsSUFBSSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUU7RUFDM0MsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsRUFBRTtJQUN6QixLQUFLQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsT0FBTyxD