UNPKG

chain-able

Version:

interfaces that describe their intentions.

709 lines (626 loc) 62.8 kB
/** * @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