UNPKG

foop

Version:

interfaces that describe their intentions.

855 lines (760 loc) 72.4 kB
/* eslint complexity: "OFF" */ /* eslint import/max-dependencies: "OFF" */ /** * @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} */ // core var SHORTHANDS_KEY = require('./deps/meta/SHORTHANDS_KEY') var ENV_DEVELOPMENT = require('./deps/env/dev') var ENV_DEBUG = require('./deps/env/debug') var ChainedMap = require('./ChainedMapBase') // 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/util/define') var ObjectKeys = require('./deps/util/keys') var ObjectAssign = require('./deps/util/assign') // utils var toarr = require('./deps/to-arr') var argumentor = require('./deps/cast/argumentor') var camelCase = require('./deps/string/camelCase') // const 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 addPoolingTo = require('./deps/cache/pooler') var defaultTo = require('./deps/cast/defaultTo') 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)) } } } var defaultToTrue = defaultTo(true) // @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 = {} var ENV_DEBUGS = true /** * ❗ using `+` will call `.build()` in a shorthand fashion * * @member MethodChain * @inheritdoc * @class * @extends {ChainedMap} * @type {Map} * * @since 4.0.0 * * @types MethodChain * @tests MethodChain * * @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) { // timer.start('methodchain') ChainedMap.call(this, parent) this.construct(parent) } if ( ChainedMap ) MethodChain.__proto__ = ChainedMap; MethodChain.prototype = Object.create( ChainedMap && ChainedMap.prototype ); MethodChain.prototype.constructor = MethodChain; MethodChain.prototype.construct = function construct (parent) { var this$1 = this; if (ENV_DEBUGS) { console.log('construct') } // @NOTE super(parent) only in constructor!!! // if (isUndefined(this.parent)) this.parent = parent // --- these are scoped with parent arg, // --- !!!!!!! they could use `this.parent` though to make them reusable !!! var set = this.set.bind(this) this.newThis = function () { return MethodChain.getPooled(this$1.parent); } // default argument... this.encase = function (x) { return set('encase', this$1.parent[x] || x || true); } this.returns = function (x, callReturns) { return set('returns', x || this$1.parent).callReturns(callReturns); } // @NOTE shorthands.bindMethods this.bind = function (target) { return set('bind', isUndefined(target) ? this$1.parent : target); } // shortest method name, could also check hasOwnProperty // once we add these, we can re-pool unscoped methods easily if (isUndefined(this.alias)) { this.setupOnce() } // need this every time... this.plugin(typesPlugin) }; MethodChain.prototype.setupOnce = function setupOnce () { var this$1 = this; if (ENV_DEBUGS) { console.log('setup once') } // ---------------- var set = this.set.bind(this) this.toNumber = function () { return this$1.build(0); } /** * @example * * chain * .method('eh') * .type(`?string`) * .type(`string[]`) * .type(`string|boolean`) * .type(`boolean[]|string[]`) * .type(`!date`) * */ this.extend(METHOD_KEYS) // shorthand this.method = this.methods = function (name) { if (this$1.length) { return this$1.build().methods(name) } else { return this$1.name(name) } } // alias this.then = this.onValid.bind(this) this.catch = this.onInvalid.bind(this) // @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); } 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 this.autoGetSet = function () { return this$1.plugin(autoGetSetPlugin); } 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 } }) } }; MethodChain.prototype.destructor = function destructor () { if (ENV_DEBUGS) { console.log('destructoor') } // remove refs to unused this.clear() this.parent = undefined // require('fliplog').quick(this) // delete this.parent // markForGarbageCollection(this) }; /** * @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) }; /** * an object that contains nestable `.type`s * they are recursively (using an optimized traversal cache) mapped to validators * ❗ this method auto-calls .build, all other method config calls should be done before it * * @TODO link to `deps/is` docs * * @version 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... * * @typedef `schema(schema: Obj): ChainAble` * * @example * * chain * .methods() * .define() * .getSet() * .onInvalid((error, arg, instance) => console.log(error)) * .schema({ * id: '?number', * users: '?object|array', * topic: '?string[]', * roles: '?array', * creator: { * name: 'string', * email: 'email', * id: 'uuid', * }, * created_at: 'date', * updated_at: 'date|date[]', * summary: 'string', * }) * * //--- valid * chain.created_at = new Date() * chain.setCreatedAt(new Date()) * * isDate(chain.created_at) === true * * //--- nestable validation 👍 * chain.merge({creator: {name: 'string'}}) * * //--- invalid * chain.updated_at = false * */ 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 MethodChain.release(this) // 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('', {}, {}) * * * @example * * let methodFactories * * ### `onSet` * * > defaults to `this.set(key, value)` * * ```ts * public onSet(fn: Fn): MethodChain * ``` * * ### `onCall` * * > defaults to .onSet ^ * * ```ts * public onCall(fn: Fn): MethodChain * ``` * * ### `onGet` * * > defaults to `this.get(key)` * * ```ts * public onGet(fn: Fn): MethodChain * ``` * */ 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 * @version 4.0.0-beta.1 <- moved to plugin * @version 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 * * */ addPoolingTo(MethodChain) // const MethodChainFunction = MethodChain.getPooled function MethodChainFunction(parent) { // return new MethodChain(parent) // require('fliplog').quick({parent}) // require('fliplog').data(MethodChain.instancePool).echo() var instance = MethodChain.getPooled(parent) // require('fliplog').data({instance}).echo() // require('fliplog').data(MethodChain.instancePool).echo() return instance } MethodChainFunction.add = function addMethodFactories(methodFactory) { ObjectAssign(methodFactories, methodFactory) } methodFactories = MethodChainFunction.add module.exports = MethodChainFunction //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWV0aG9kQ2hhaW4uanMiLCJzb3VyY2VzIjpbIk1ldGhvZENoYWluLmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludCBjb21wbGV4aXR5OiBcIk9GRlwiICovXG4vKiBlc2xpbnQgaW1wb3J0L21heC1kZXBlbmRlbmNpZXM6IFwiT0ZGXCIgKi9cblxuLyoqXG4gKiBAVE9ETyBjbGFyaWZ5IC5zZXQgdnMgLmNhbGxcbiAqIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vaWx1d2F0YXIvamF2YS1kZXNpZ24tcGF0dGVybnMvdHJlZS9tYXN0ZXIvcHJvcGVydHkgcHJvcGVydHktcGF0dGVybn1cbiAqIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vaWx1d2F0YXIvamF2YS1kZXNpZ24tcGF0dGVybnMvdHJlZS9tYXN0ZXIvcHJvdG90eXBlIHByb3RvdHlwZS1wYXR0ZXJufVxuICoge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9pbHV3YXRhci9qYXZhLWRlc2lnbi1wYXR0ZXJucy90cmVlL21hc3Rlci9zdGVwLWJ1aWxkZXIgc3RlcC1idWlsZGVyLXBhdHRlcm59XG4gKiB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2lsdXdhdGFyL2phdmEtZGVzaWduLXBhdHRlcm5zL3RyZWUvbWFzdGVyL2J1aWxkZXIgYnVpbGRlci1wYXR0ZXJufVxuICoge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9hZGR5b3NtYW5pL2Vzc2VudGlhbC1qcy1kZXNpZ24tcGF0dGVybnMvYmxvYi9tYXN0ZXIvZGlhZ3JhbXMvbWl4aW5zLnBuZyBtaXhpbi1wbmd9XG4gKiB7QGxpbmsgaHR0cHM6Ly9zb3VyY2VtYWtpbmcuY29tL2Rlc2lnbl9wYXR0ZXJucy9jcmVhdGlvbmFsX3BhdHRlcm5zIGNyZWF0aW9uYWwtcGF0dGVybnN9XG4gKiB7QGxpbmsgaHR0cHM6Ly9zb3VyY2VtYWtpbmcuY29tL2Rlc2lnbl9wYXR0ZXJucy9mYWN0b3J5X21ldGhvZCBmYWN0b3J5LW1ldGhvZH1cbiAqIHtAbGluayBodHRwczovL21lZGl1bS5jb20vamF2YXNjcmlwdC1zY2VuZS9qYXZhc2NyaXB0LWZhY3RvcnktZnVuY3Rpb25zLXZzLWNvbnN0cnVjdG9yLWZ1bmN0aW9ucy12cy1jbGFzc2VzLTJmMjJjZWRkZjMzZSBjb25zdHJ1Y3RvcnN9XG4gKiB7QGxpbmsgaHR0cHM6Ly93d3cuc2l0ZXBvaW50LmNvbS9mYWN0b3J5LWZ1bmN0aW9ucy1qYXZhc2NyaXB0LyBqcy1mYWN0b3J5LWZ1bmN0aW9uc31cbiAqL1xuXG4vLyBjb3JlXG5jb25zdCBTSE9SVEhBTkRTX0tFWSA9IHJlcXVpcmUoJy4vZGVwcy9tZXRhL1NIT1JUSEFORFNfS0VZJylcbmNvbnN0IEVOVl9ERVZFTE9QTUVOVCA9IHJlcXVpcmUoJy4vZGVwcy9lbnYvZGV2JylcbmNvbnN0IEVOVl9ERUJVRyA9IHJlcXVpcmUoJy4vZGVwcy9lbnYvZGVidWcnKVxuY29uc3QgQ2hhaW5lZE1hcCA9IHJlcXVpcmUoJy4vQ2hhaW5lZE1hcEJhc2UnKVxuLy8gcGx1Z2luc1xuY29uc3Qgc2NoZW1hTWV0aG9kID0gcmVxdWlyZSgnLi9wbHVnaW5zL3NjaGVtYScpXG5jb25zdCB0eXBlc1BsdWdpbiA9IHJlcXVpcmUoJy4vcGx1Z2lucy90eXBlcycpXG5jb25zdCBvYmpQbHVnaW4gPSByZXF1aXJlKCcuL3BsdWdpbnMvb2JqJylcbmNvbnN0IGVuY2FzZVBsdWdpbiA9IHJlcXVpcmUoJy4vcGx1Z2lucy9lbmNhc2UnKVxuY29uc3QgZGVjb3JhdGVQbHVnaW4gPSByZXF1aXJlKCcuL3BsdWdpbnMvZGVjb3JhdGUnKVxuY29uc3QgYXV0b0luY3JlbWVudFBsdWdpbiA9IHJlcXVpcmUoJy4vcGx1Z2lucy9hdXRvSW5jcmVtZW50JylcbmNvbnN0IGF1dG9HZXRTZXRQbHVnaW4gPSByZXF1aXJlKCcuL3BsdWdpbnMvYXV0b0dldFNldCcpXG4vLyBjb25zdCB2YWxpZGF0b3JCdWlsZGVyID0gcmVxdWlyZSgnLi9kZXBzL3ZhbGlkYXRvcnMvdmFsaWRhdG9yQnVpbGRlcicpXG4vLyBvYmpcbmNvbnN0IGhhc093blByb3BlcnR5ID0gcmVxdWlyZSgnLi9kZXBzL3V0aWwvaGFzT3duUHJvcGVydHknKVxuY29uc3QgZ2V0RGVzY3JpcHRvciA9IHJlcXVpcmUoJy4vZGVwcy91dGlsL2dldERlc2NyaXB0b3InKVxuY29uc3QgT2JqZWN0RGVmaW5lID0gcmVxdWlyZSgnLi9kZXBzL3V0aWwvZGVmaW5lJylcbmNvbnN0IE9iamVjdEtleXMgPSByZXF1aXJlKCcuL2RlcHMvdXRpbC9rZXlzJylcbmNvbnN0IE9iamVjdEFzc2lnbiA9IHJlcXVpcmUoJy4vZGVwcy91dGlsL2Fzc2lnbicpXG4vLyB1dGlsc1xuY29uc3QgdG9hcnIgPSByZXF1aXJlKCcuL2RlcHMvdG8tYXJyJylcbmNvbnN0IGFyZ3VtZW50b3IgPSByZXF1aXJlKCcuL2RlcHMvY2FzdC9hcmd1bWVudG9yJylcbmNvbnN0IGNhbWVsQ2FzZSA9IHJlcXVpcmUoJy4vZGVwcy9zdHJpbmcvY2FtZWxDYXNlJylcbi8vIGNvbnN0IG1hcmtGb3JHYXJiYWdlQ29sbGVjdGlvbiA9IHJlcXVpcmUoJy4vZGVwcy9nYycpXG4vLyBpc1xuY29uc3QgaXNPYmogPSByZXF1aXJlKCcuL2RlcHMvaXMvb2JqJylcbmNvbnN0IGlzQXJyYXkgPSByZXF1aXJlKCcuL2RlcHMvaXMvYXJyYXknKVxuY29uc3QgaXNVbmRlZmluZWQgPSByZXF1aXJlKCcuL2RlcHMvaXMvdW5kZWZpbmVkJylcbmNvbnN0IGlzVHJ1ZSA9IHJlcXVpcmUoJy4vZGVwcy9pcy90cnVlJylcbmNvbnN0IGlzRmFsc2UgPSByZXF1aXJlKCcuL2RlcHMvaXMvZmFsc2UnKVxuY29uc3QgaXNPYmpXaXRoS2V5cyA9IHJlcXVpcmUoJy4vZGVwcy9pcy9vYmpXaXRoS2V5cycpXG5jb25zdCBhZGRQb29saW5nVG8gPSByZXF1aXJlKCcuL2RlcHMvY2FjaGUvcG9vbGVyJylcbmNvbnN0IGRlZmF1bHRUbyA9IHJlcXVpcmUoJy4vZGVwcy9jYXN0L2RlZmF1bHRUbycpXG5cbmNvbnN0IERFRkFVTFRFRF9LRVkgPSAnZGVmYXVsdGVkJ1xuY29uc3QgTUVUSE9EX0tFWVMgPSBbXG4gICdvbkludmFsaWQnLFxuICAnb25WYWxpZCcsXG4gICdpbml0aWFsJyxcbiAgJ2RlZmF1bHQnLFxuICAndHlwZScsXG4gICdjYWxsUmV0dXJucycsXG4gICd0YXJnZXQnLFxuICAnb25TZXQnLFxuICAnb25DYWxsJyxcbiAgJ29uR2V0Jyxcbl1cblxuLy8gY29uc3QgU0VUX0tFWSA9IE1FVEhPRF9LRVlTWzBdXG5cbmZ1bmN0aW9uIGdldFNldEZhY3RvcnkoX3RoaXMsIG5hbWUsIGRlc2MpIHtcbiAgX3RoaXNbY2FtZWxDYXNlKGBzZXQtJHtuYW1lfWApXSA9IGRlc2Muc2V0XG4gIF90aGlzW2NhbWVsQ2FzZShgZ2V0LSR7bmFtZX1gKV0gPSBkZXNjLmdldFxufVxuXG5mdW5jdGlvbiBhbGlhc0ZhY3RvcnkobmFtZSwgcGFyZW50LCBhbGlhc2VzKSB7XG4gIGlmICghaXNVbmRlZmluZWQoYWxpYXNlcykpIHtcbiAgICBmb3IgKGxldCBhID0gMDsgYSA8IGFsaWFzZXMubGVuZ3RoOyBhKyspIHtcbiAgICAgIE9iamVjdERlZmluZShwYXJlbnQsIGFsaWFzZXNbYV0sIGdldERlc2NyaXB0b3IocGFyZW50LCBuYW1lKSlcbiAgICB9XG4gIH1cbn1cblxuY29uc3QgZGVmYXVsdFRvVHJ1ZSA9IGRlZmF1bHRUbyh0cnVlKVxuXG4vLyBAVE9ETyB0byB1c2UgYXMgYSBmdW5jdGlvblxuLy8gZnVuY3Rpb24gX21ldGhvZHMoKSB7fVxuLy8gX21ldGhvZHMudXNlKG9iaikge1xuLy8gICB0aGlzLm9iaiA9IG9ialxuLy8gICByZXR1cm4gX21ldGhvZHNcbi8vIH1cbi8vIF9tZXRob2RzLmV4dGVuZCA9IF9tZXRob2RzLnVzZVxuLy8gX21ldGhvZHMubWV0aG9kcyA9IGZ1bmN0aW9uKG1ldGhvZHMpIHtcbi8vICAgcmV0dXJuIG5ldyBNZXRob2RDaGFpbih0aGlzLm9iailcbi8vIH1cblxubGV0IG1ldGhvZEZhY3RvcmllcyA9IHt9XG5jb25zdCBFTlZfREVCVUdTID0gdHJ1ZVxuXG4vKipcbiAqIOKdlyB1c2luZyBgK2Agd2lsbCBjYWxsIGAuYnVpbGQoKWAgaW4gYSBzaG9ydGhhbmQgZmFzaGlvblxuICpcbiAqIEBtZW1iZXIgTWV0aG9kQ2hhaW5cbiAqIEBpbmhlcml0ZG9jXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIHtDaGFpbmVkTWFwfVxuICogQHR5cGUge01hcH1cbiAqXG4gKiBAc2luY2UgNC4wLjBcbiAqXG4gKiBAdHlwZXMgTWV0aG9kQ2hhaW5cbiAqIEB0ZXN0cyBNZXRob2RDaGFpblxuICpcbiAqIEBUT0RPIG1heWJlIGFic3RyYWN0IHRoZSBtb3N0IHJlLXVzYWJsZSBjb3JlIGFzIGEgcHJvdGVjdGVkIGNsYXNzXG4gKiAgICAgICAgc28gdGhlIHNob3J0aGFuZHMgY291bGQgYmUgdXNlZCwgYW5kIG1vcmUgZnVuY3Rpb25hbGl0eSBtYWRlIGV4dGVybmFsXG4gKiBAVE9ETyBuZWVkIHRvIHNlcGFyYXRlIHNjaGVtYSBmcm9tIGhlcmUgYXMgZXh0ZXJuYWwgZnVuY3Rpb25hbGl0eSAmIGFkZCAuYWRkXG4gKiBAVE9ETyAucHJvcCAtIGZvciB0aGluZ3Mgb24gdGhlIGluc3RhbmNlLCBub3QgaW4gdGhlIHN0b3JlP1xuICogICAgICAgICEhISAuc3BvbmdlIC0gYWJzb3JuIHByb3BlcnRpZXMgaW50byB0aGUgc3RvcmVcbiAqL1xuY2xhc3MgTWV0aG9kQ2hhaW4gZXh0ZW5kcyBDaGFpbmVkTWFwIHtcbiAgY29uc3RydWN0b3IocGFyZW50KSB7XG4gICAgLy8gdGltZXIuc3RhcnQoJ21ldGhvZGNoYWluJylcbiAgICBzdXBlcihwYXJlbnQpXG4gICAgdGhpcy5jb25zdHJ1Y3QocGFyZW50KVxuICB9XG5cbiAgY29uc3RydWN0KHBhcmVudCkge1xuICAgIGlmIChFTlZfREVCVUdTKSB7XG4gICAgICBjb25zb2xlLmxvZygnY29uc3RydWN0JylcbiAgICB9XG4gICAgLy8gQE5PVEUgc3VwZXIocGFyZW50KSBvbmx5IGluIGNvbnN0cnVjdG9yISEhXG4gICAgLy8gaWYgKGlzVW5kZWZpbmVkKHRoaXMucGFyZW50KSlcbiAgICB0aGlzLnBhcmVudCA9IHBhcmVudFxuXG4gICAgLy8gLS0tIHRoZXNlIGFyZSBzY29wZWQgd2l0aCBwYXJlbnQgYXJnLFxuICAgIC8vIC0tLSAhISEhISEhIHRoZXkgY291bGQgdXNlIGB0aGlzLnBhcmVudGAgdGhvdWdoIHRvIG1ha2UgdGhlbSByZXVzYWJsZSAhISFcbiAgICBjb25zdCBzZXQgPSB0aGlzLnNldC5iaW5kKHRoaXMpXG4gICAgdGhpcy5uZXdUaGlzID0gKCkgPT4gTWV0aG9kQ2hhaW4uZ2V0UG9vbGVkKHRoaXMucGFyZW50KVxuICAgIC8vIGRlZmF1bHQgYXJndW1lbnQuLi5cbiAgICB0aGlzLmVuY2FzZSA9IHggPT4gc2V0KCdlbmNhc2UnLCB0aGlzLnBhcmVudFt4XSB8fCB4IHx8IHRydWUpXG4gICAgdGhpcy5yZXR1cm5zID0gKHgsIGNhbGxSZXR1cm5zKSA9PlxuICAgICAgc2V0KCdyZXR1cm5zJywgeCB8fCB0aGlzLnBhcmVudCkuY2FsbFJldHVybnMoY2FsbFJldHVybnMpXG5cbiAgICAvLyBATk9URSBzaG9ydGhhbmRzLmJpbmRNZXRob2RzXG4gICAgdGhpcy5iaW5kID0gdGFyZ2V0ID0+XG4gICAgICBzZXQoJ2JpbmQnLCBpc1VuZGVmaW5lZCh0YXJnZXQpID8gdGhpcy5wYXJlbnQgOiB0YXJnZXQpXG5cbiAgICAvLyBzaG9ydGVzdCBtZXRob2QgbmFtZSwgY291bGQgYWxzbyBjaGVjayBoYXNPd25Qcm9wZXJ0eVxuICAgIC8vIG9uY2Ugd2UgYWRkIHRoZXNlLCB3ZSBjYW4gcmUtcG9vbCB1bnNjb3BlZCBtZXRob2RzIGVhc2lseVxuICAgIGlmIChpc1VuZGVmaW5lZCh0aGlzLmFsaWFzKSkgdGhpcy5zZXR1cE9uY2UoKVxuXG4gICAgLy8gbmVlZCB0aGlzIGV2ZXJ5IHRpbWUuLi5cbiAgICB0aGlzLnBsdWdpbih0eXBlc1BsdWdpbilcbiAgfVxuXG4gIHNldHVwT25jZSgpIHtcbiAgICBpZiAoRU5WX0RFQlVHUykge1xuICAgICAgY29uc29sZS5sb2coJ3NldHVwIG9uY2UnKVxuICAgIH1cblxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS1cbiAgICBjb25zdCBzZXQgPSB0aGlzLnNldC5iaW5kKHRoaXMpXG5cbiAgICB0aGlzLnRvTnVtYmVyID0gKCkgPT4gdGhpcy5idWlsZCgwKVxuXG4gICAgLyoqXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqICBjaGFpblxuICAgICAqICAgICAubWV0aG9kKCdlaCcpXG4gICAgICogICAgIC50eXBlKGA/c3RyaW5nYClcbiAgICAgKiAgICAgLnR5cGUoYHN0cmluZ1tdYClcbiAgICAgKiAgICAgLnR5cGUoYHN0cmluZ3xib29sZWFuYClcbiAgICAgKiAgICAgLnR5cGUoYGJvb2xlYW5bXXxzdHJpbmdbXWApXG4gICAgICogICAgIC50eXBlKGAhZGF0ZWApXG4gICAgICpcbiAgICAgKi9cbiAgICB0aGlzLmV4dGVuZChNRVRIT0RfS0VZUylcblxuICAgIC8vIHNob3J0aGFuZFxuICAgIHRoaXMubWV0aG9kID0gdGhpcy5tZXRob2RzID0gbmFtZSA9PiB7XG4gICAgICBpZiAodGhpcy5sZW5ndGgpIHJldHVybiB0aGlzLmJ1aWxkKCkubWV0aG9kcyhuYW1lKVxuICAgICAgZWxzZSByZXR1cm4gdGhpcy5uYW1lKG5hbWUpXG4gICAgfVxuXG4gICAgLy8gYWxpYXNcbiAgICB0aGlzLnRoZW4gPSB0aGlzLm9uVmFsaWQuYmluZCh0aGlzKVxuICAgIHRoaXMuY2F0Y2ggPSB0aGlzLm9uSW52YWxpZC5iaW5kKHRoaXMpXG5cbiAgICAvLyBATk9URSByZXBsYWNlcyBzaG9ydGhhbmRzLmNoYWluV3JhcFxuICAgIHRoaXMuY2hhaW5hYmxlID0gdGhpcy5yZXR1cm5zXG5cbiAgICAvKipcbiAgICAgKiBAZGVzYyBhbGlhcyBtZXRob2RzXG4gICAgICogQHNpbmNlIDIuMC4wXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtzdHJpbmcgfCBBcnJheTxzdHJpbmc+fSBhbGlhc2VzIGFsaWFzZXMgdG8gcmVtYXAgdG8gdGhlIGN1cnJlbnQgbWV0aG9kIGJlaW5nIGJ1aWx0XG4gICAgICogQHJldHVybiB7TWV0aG9kQ2hhaW59IEBjaGFpbmFibGVcbiAgICAgKlxuICAgICAqIEBOT1RFIHRoZXNlIHdvdWxkIGJlIC50cmFuc2Zvcm1cbiAgICAgKlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiAgICAgY29uc3QgY2hhaW4gPSBuZXcgQ2hhaW4oKVxuICAgICAqICAgICBjaGFpbi5tZXRob2RzKFsnY2FuYWRhJ10pLmFsaWFzKFsnZWgnXSkuYnVpbGQoKVxuICAgICAqICAgICBjaGFpbi5laCgnYWN0dWFsbHkuLi5jYW5hZGEgby5vJylcbiAgICAgKiAgICAgY2hhaW4uZ2V0KCdjYW5hZGEnKVxuICAgICAqICAgICAvLz0+ICdhY3R1YWxseS4uLmNhbmFkYSBvLm8nKVxuICAgICAqXG4gICAgICovXG4gICAgdGhpcy5hbGlhcyA9IGFsaWFzZXMgPT5cbiAgICAgIHRoaXMudGFwKCdhbGlhcycsIChvbGQsIG1lcmdlKSA9PiBtZXJnZShvbGQsIHRvYXJyKGFsaWFzZXMpKSlcbiAgICB0aGlzLnBsdWdpbiA9IHBsdWdpbiA9PlxuICAgICAgdGhpcy50YXAoJ3BsdWdpbnMnLCAob2xkLCBtZXJnZSkgPT4gbWVyZ2Uob2xkLCB0b2FycihwbHVnaW4pKSlcblxuICAgIHRoaXMuY2FtZWxDYXNlID0gKCkgPT4gc2V0KCdjYW1lbCcsIHRydWUpXG5cbiAgICB0aGlzLmRlZmluZSA9IHggPT4gc2V0KCdkZWZpbmUnLCBkZWZhdWx0VG9UcnVlKHgpKVxuICAgIHRoaXMuZ2V0U2V0ID0geCA9PiBzZXQoJ2dldFNldCcsIGRlZmF1bHRUb1RydWUoeCkpXG5cbiAgICAvLyBAVE9ETyB1bmxlc3MgdGhlc2UgdXNlIHNjb3BlZCB2YXJzLCB0aGV5IHNob3VsZCBiZSBvbiBwcm90b1xuICAgIHRoaXMuYXV0b0dldFNldCA9ICgpID0+IHRoaXMucGx1Z2luKGF1dG9HZXRTZXRQbHVnaW4pXG5cbiAgICBpZiAoaXNPYmpXaXRoS2V5cyhtZXRob2RGYWN0b3JpZXMpKSB7XG4gICAgICBPYmplY3RLZXlzKG1ldGhvZEZhY3RvcmllcykuZm9yRWFjaChmYWN0b3J5TmFtZSA9PiB7XG4gICAgICAgIHRoaXNbZmFjdG9yeU5hbWVdID0gYXJnID0+IG1ldGhvZEZhY3Rvcmllc1tmYWN0b3J5TmFtZV0uY2FsbCh0aGlzLCBhcmcpXG4gICAgICAgIGlmIChFTlZfREVWRUxPUE1FTlQpIHtcbiAgICAgICAgICB0aGlzW2ZhY3RvcnlOYW1lXS5tZXRob2RGYWN0b3J5ID0gdHJ1ZVxuICAgICAgICB9XG4gICAgICB9KVxuICAgIH1cbiAgfVxuXG4gIGRlc3RydWN0b3IoKSB7XG4gICAgaWYgKEVOVl9ERUJVR1MpIHtcbiAgICAgIGNvbnNvbGUubG9nKCdkZXN0cnVjdG9vcicpXG4gICAgfVxuXG4gICAgLy8gcmVtb3ZlIHJlZnMgdG8gdW51c2VkXG4gICAgdGhpcy5jbGVhcigpXG4gICAgdGhpcy5wYXJlbnQgPSB1bmRlZmluZWRcbiAgICAvLyByZXF1aXJlKCdmbGlwbG9nJykucXVpY2sodGhpcylcbiAgICAvLyBkZWxldGUgdGhpcy5wYXJlbnRcbiAgICAvLyBtYXJrRm9yR2FyYmFnZUNvbGxlY3Rpb24odGhpcylcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzYyBzZXR1cCBtZXRob2RzIHRvIGJ1aWxkXG4gICAqIEBjYXRlZ29yeSBidWlsZGVyXG4gICAqIEBtZW1iZXJPZiBNZXRob2RDaGFpblxuICAgKlxuICAgKiBAc2luY2UgNC4wLjAtYmV0YS4xIDwtIG1vdmVkIHRvIHBsdWdpblxuICAgKiBAc2luY2UgNC4wLjBcbiAgICpcbiAgICogQHBhcmFtICB7c3RyaW5nIHwgT2JqZWN0IHwgQXJyYXk8c3RyaW5nPn0gbWV0aG9kcyBtZXRob2QgbmFtZXMgdG8gYnVpbGRcbiAgICogQHJldHVybiB7TWV0aG9kQ2hhaW59IEBjaGFpbmFibGVcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgdmFyIG9iaiA9IHt9XG4gICAqICAgIG5ldyBNZXRob2RDaGFpbihvYmopLm5hbWUoJ2VoJykuYnVpbGQoKVxuICAgKiAgICB0eXBlb2Ygb2JqLmVoXG4gICAqICAgIC8vPT4gJ2Z1bmN0aW9uJ1xuICAgKlxuICAgKi9cbiAgbmFtZShtZXRob2RzKSB7XG4gICAgbGV0IG5hbWVzID0gbWV0aG9kc1xuXG4gICAgLyoqXG4gICAgICogQGRlc2MgdGhpcyBpcyBhIHBsdWdpbiBmb3IgYnVpbGRpbmcgbWV0aG9kc1xuICAgICAqICAgICAgIHNjaGVtYSBkZWZhdWx0cyB2YWx1ZSB0byBgLnR5cGVgXG4gICAgICogICAgICAgdGhpcyBkZWZhdWx0cyB2YWx1ZXMgdG8gYC5vbkNhbGxgXG4gICAgICovXG4gICAgaWYgKCFpc0FycmF5KG1ldGhvZHMpICYmIGlzT2JqKG1ldGhvZHMpKSB7XG4gICAgICBuYW1lcyA9IE9iamVjdEtleXMobWV0aG9kcylcbiAgICAgIGZvciAobGV0IG5hbWUgPSAwOyBuYW1lIDwgbmFtZXMubGVuZ3RoOyBuYW1lKyspIHtcbiAgICAgICAgdGhpcy5wbHVnaW4ob2JqUGx1Z2luLmNhbGwodGhpcywgbWV0aG9kcywgbmFtZXNbbmFtZV0pKVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5zZXQoJ25hbWVzJywgbmFtZXMpXG4gIH1cblxuICAvKipcbiAgICogYW4gb2JqZWN0IHRoYXQgY29udGFpbnMgbmVzdGFibGUgYC50eXBlYHNcbiAgICogdGhleSBhcmUgcmVjdXJzaXZlbHkgKHVzaW5nIGFuIG9wdGltaXplZCB0cmF2ZXJzYWwgY2FjaGUpIG1hcHBlZCB0byB2YWxpZGF0b3JzXG4gICAqIOKdlyB0aGlzIG1ldGhvZCBhdXRvLWNhbGxzIC5idWlsZCwgYWxsIG90aGVyIG1ldGhvZCBjb25maWcgY2FsbHMgc2hvdWxkIGJlIGRvbmUgYmVmb3JlIGl0XG4gICAqXG4gICAqIEBUT0RPIGxpbmsgdG8gYGRlcHMvaXNgIGRvY3NcbiAgICpcbiAgICogQHZlcnNpb24gNC4wLjAtYmV0YS4xIDwtIG1vdmVkIHRvIHBsdWdpblxuICAgKiBAc2luY2UgNC4wLjBcbiAgICpcbiAgICogQGNhdGVnb3J5IHR5cGVzXG4gICAqIEBtZW1iZXJPZiBNZXRob2RDaGFpblxuICAgKlxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqIHNjaGVtYVxuICAgKiBAcmV0dXJuIHtNZXRob2RDaGFpbn0gQGNoYWluYWJsZVxuICAgKlxuICAgKiBAVE9ETyBtb3ZlIG91dCBpbnRvIGEgcGx1Z2luIHRvIHNob3cgaG93IGVhc3kgaXQgaXMgdG8gdXNlIGEgcGx1Z2luXG4gICAqICAgICAgIGFuZCBtYWtlIGl0IGFibGUgdG8gYmUgc3BsaXQgb3V0IGZvciBzaXplIHdoZW4gbmVlZGVkXG4gICAqXG4gICAqIEBUT0RPIGluaGVyaXQgcHJvcGVydGllcyAoaW4gcGx1Z2luLCBmb3IgZWFjaCBrZXkpXG4gICAqICAgICAgIGZyb20gdGhpcyBmb3Igc2F5LCBkb3RQcm9wLCBnZXRTZXRcbiAgICpcbiAgICogQFRPRE8gdmVyeSBAaW1wb3J0YW50XG4gICAqICAgICAgIHRoYXQgd2Ugc2V0dXAgc2NoZW1hIHZhbGlkYXRpb24gYXQgdGhlIGhpZ2hlc3Qgcm9vdCBmb3IgdmFsaWRhdGlvblxuICAgKiAgICAgICBhbmQgdGhlbiBoYXZlIHNvbWUgZGVtbyBmb3IgaG93IHRvIHZhbGlkYXRlIG9uIHNldCB1c2luZyBzYXkgbW9ieFxuICAgKiAgICAgICBvYnNlcnZhYmxlcyBmb3IgYWxsIHRoZSB3YXkgZG93bi4uLlxuICAgKlxuICAgKiBAdHlwZWRlZiBgc2NoZW1hKHNjaGVtYTogT2JqKTogQ2hhaW5BYmxlYFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICBjaGFpblxuICAgKiAgICAgIC5tZXRob2RzKClcbiAgICogICAgICAuZGVmaW5lKClcbiAgICogICAgICAuZ2V0U2V0KClcbiAgICogICAgICAub25JbnZhbGlkKChlcnJvciwgYXJnLCBpbnN0YW5jZSkgPT4gY29uc29sZS5sb2coZXJyb3IpKVxuICAgKiAgICAgIC5zY2hlbWEoe1xuICAgKiAgICAgICAgaWQ6ICc/bnVtYmVyJyxcbiAgICogICAgICAgIHVzZXJzOiAnP29iamVjdHxhcnJheScsXG4gICAqICAgICAgICB0b3BpYzogJz9zdHJpbmdbXScsXG4gICAqICAgICAgICByb2xlczogJz9hcnJheScsXG4gICAqICAgICAgICBjcmVhdG9yOiB7XG4gICAqICAgICAgICAgIG5hbWU6ICdzdHJpbmcnLFxuICAgKiAgICAgICAgICBlbWFpbDogJ2VtYWlsJyxcbiAgICogICAgICAgICAgaWQ6ICd1dWlkJyxcbiAgICogICAgICAgIH0sXG4gICAqICAgICAgICBjcmVhdGVkX2F0OiAnZGF0ZScsXG4gICAqICAgICAgICB1cGRhdGVkX2F0OiAnZGF0ZXxkYXRlW10nLFxuICAgKiAgICAgICAgc3VtbWFyeTogJ3N0cmluZycsXG4gICAqICAgICAgfSlcbiAgICpcbiAgICogICAgLy8tLS0gdmFsaWRcbiAgICogICAgY2hhaW4uY3JlYXRlZF9hdCA9IG5ldyBEYXRlKClcbiAgICogICAgY2hhaW4uc2V0Q3JlYXRlZEF0KG5ldyBEYXRlKCkpXG4gICAqXG4gICAqICAgIGlzRGF0ZShjaGFpbi5jcmVhdGVkX2F0KSA9PT0gdHJ1ZVxuICAgKlxuICAgKiAgICAvLy0tLSBuZXN0YWJsZSB2YWxpZGF0aW9uIPCfkY1cbiAgICogICAgY2hhaW4ubWVyZ2Uoe2NyZWF0b3I6IHtuYW1lOiAnc3RyaW5nJ319KVxuICAgKlxuICAgKiAgICAvLy0tLSBpbnZhbGlkXG4gICAqICAgIGNoYWluLnVwZGF0ZWRfYXQgPSBmYWxzZVxuICAgKlxuICAgKi9cbiAgc2NoZW1hKG9iaikge1xuICAgIHJldHVybiBzY2hlbWFNZXRob2QuY2FsbCh0aGlzLCBvYmopXG4gIH1cblxuICAvKipcbiAgICogQGRlc2Mgc2V0IHRoZSBhY3R1YWwgbWV0aG9kLCBhbHNvIG5lZWQgLmNvbnRleHQgLSB1c2UgLnBhcmVudFxuICAgKiBAbWVtYmVyT2YgTWV0aG9kQ2hhaW5cbiAgICogQHNpbmNlIDQuMC4wXG4gICAqXG4gICAqIEBwYXJhbSAge2FueX0gW3JldHVyblZhbHVlPXVuZGVmaW5lZF0gcmV0dXJuZWQgYXQgdGhlIGVuZCBvZiB0aGUgZnVuY3Rpb24gZm9yIGVhc2Ugb2YgdXNlXG4gICAqIEByZXR1cm4ge01ldGhvZENoYWlufSBAY2hhaW5hYmxlXG4gICAqXG4gICAqIEBUT0RPIGlmIHBhc3NpbmcgaW4gYSBuYW1lIHRoYXQgYWxyZWFkeSBleGlzdHMsIG9wZXJhdGlvbnMgYXJlIGRlY29yYXRpb25zLi4uIChwYXJ0aWFsbHkgZG9uZSlcbiAgICogQHNlZSBodHRwczovL2dpdGh1Yi5jb20vaWx1d2F0YXIvamF2YS1kZXNpZ24tcGF0dGVybnMvdHJlZS9tYXN0ZXIvc3RlcC1idWlsZGVyXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgIHZhciBvYmogPSB7fVxuICAgKiAgICBjb25zdCBvbmUgPSBuZXcgTWV0aG9kQ2hhaW4ob2JqKS5tZXRob2RzKCdlaCcpLmdldFNldCgpLmJ1aWxkKDEpXG4gICAqICAgIC8vPT4gMVxuICAgKlxuICAgKiAgICB0eXBlb2Ygb2JqLmdldEVoXG4gICAqICAgIC8vPT4gJ2Z1bmN0aW9uJ1xuICAgKlxuICAgKi9cbiAgYnVpbGQocmV0dXJuVmFsdWUpIHtcbiAgICBjb25zdCBwYXJlbnQgPSB0aGlzLnBhcmVudFxuICAgIGNvbnN0IG5hbWVzID0gdG9hcnIodGhpcy5nZXQoJ25hbWVzJykpXG4gICAgY29uc3Qgc2hvdWxkVGFwTmFtZSA9IHRoaXMuZ2V0KCdjYW1lbCcpXG5cbiAgICBmb3IgKGxldCBuYW1lID0gMDsgbmFtZSA8IG5hbWVzLmxlbmd0aDsgbmFtZSsrKSB7XG4gICAgICB0aGlzLl9idWlsZChzaG91bGRUYXBOYW1lID8gY2FtZWxDYXNlKG5hbWVzW25hbWVdKSA6IG5hbWVzW25hbWVdLCBwYXJlbnQpXG4gICAgfVxuXG4gICAgLy8gdGltZXIuc3RvcCgnbWV0aG9kY2hhaW4nKS5sb2coJ21ldGhvZGNoYWluJykuc3RhcnQoJ2djJylcblxuICAgIC8vIHJlbW92ZSByZWZzIHRvIHVudXNlZFxuICAgIHRoaXMuY2xlYXIoKVxuICAgIGRlbGV0ZSB0aGlzLnBhcmVudFxuICAgIE1ldGhvZENoYWluLnJlbGVhc2UodGhpcylcblxuICAgIC8vIG1hcmtGb3JHYXJiYWdlQ29sbGVjdGlvbih0aGlzKVxuXG4gICAgLy8gdmVyeSBmYXN0IC0gdGltZXIgJiBlbnN1cmluZyBwcm9wcyBhcmUgY2xlYW5lZFxuICAgIC8vIHRpbWVyLnN0b3AoJ2djJykubG9nKCdnYycpXG4gICAgLy8gcmVxdWlyZSgnZmxpcGxvZycpLnF1aWNrKHRoaXMpXG5cbiAgICByZXR1cm4gaXNVbmRlZmluZWQocmV0dXJuVmFsdWUpID8gcGFyZW50IDogcmV0dXJuVmFsdWVcbiAgfVxuXG4gIC8qKlxuICAgKiBAbWVtYmVyT2YgTWV0aG9kQ2hhaW5cbiAgICpcbiAgICogQHNpbmNlIDQuMC4wXG4gICAqIEBwcm90ZWN0ZWRcbiAgICogQHBhcmFtIHtQcmltaXRpdmV9IG5hbWUgbWV0aG9kIG5hbWVcbiAgICogQHBhcmFtIHtPYmplY3R9IHBhcmVudCBiZWluZyBkZWNvcmF0ZWRcbiAgICogQHBhcmFtIHtPYmplY3R9IGJ1aWx0IG1ldGhvZCBiZWluZyBidWlsdFxuICAgKiBAcmV0dXJuIHt2b2lkfVxuICAgKlxuICAgKiBAVE9ETyAgb3B0aW1pemUgdGhlIHNpemUgb2YgdGhpc1xuICAgKiAgICAgICAgd2l0aCBzb21lIGJpdHdpc2Ugb3BlcmF0b3JzXG4gICAqICAgICAgICBoYXNoaW5nIHRoZSB0aGluZ3MgdGhhdCBoYXZlIGJlZW4gZGVmYXVsdGVkXG4gICAqICAgICAgICBhbHNvIGNvdWxkIGJlIHBsdWdpblxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgLl9kZWZhdWx0cygnJywge30sIHt9KVxuICAgKlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgIGxldCBtZXRob2RGYWN0b3JpZXNcbiAgICpcbiAgICogICAjIyMgYG9uU2V0YFxuICAgKlxuICAgKiAgID4gZGVmYXVsdHMgdG8gYHRoaXMuc2V0KGtleSwgdmFsdWUpYFxuICAgKlxuICAgKiAgIGBgYHRzXG4gICAqICAgcHVibGljIG9uU2V0KGZuOiBGbik6IE1ldGhvZENoYWluXG4gICAqICAgYGBgXG4gICAqXG4gICAqICAgIyMjIGBvbkNhbGxgXG4gICAqXG4gICAqICAgPiBkZWZhdWx0cyB0byAub25TZXQgXlxuICAgKlxuICAgKiAgIGBgYHRzXG4gICAqICAgcHVibGljIG9uQ2FsbChmbjogRm4pOiBNZXRob2RDaGFpblxuICAgKiAgIGBgYFxuICAgKlxuICAgKiAgICMjIyBgb25HZXRgXG4gICAqXG4gICAqICAgPiBkZWZhdWx0cyB0byBgdGhpcy5nZXQoa2V5KWBcbiAgICpcbiAgICogICBgYGB0c1xuICAgKiAgIHB1YmxpYyBvbkdldChmbjogRm4pOiBNZXRob2RDaGFpblxuICAgKiAgIGBgYFxuICAgKlxuICAgKi9cbiAgX2RlZmF1bHRzKG5hbWUsIHBhcmVudCwgYnVpbHQpIHtcbiAgICAvLyBkZWZhdWx0c1xuICAgIGNvbnN0IGRlZmF1bHRPblNldCA9IGFyZyA9PiBwYXJlbnQuc2V0KG5hbWUsIGFyZylcbiAgICBjb25zdCBkZWZhdWx0T25HZXQgPSAoKSA9PiBwYXJlbnQuZ2V0KG5hbWUpXG5cbiAgICAvLyBzbyB3ZSBrbm93IGlmIHdlIGRlZmF1bHRlZCB0aGVtXG4gICAgZGVmYXVsdE9uU2V0W0RFRkFVTFRFRF9LRVldID0gdHJ1ZVxuICAgIGRlZmF1bHRPbkdldFtERUZBVUxURURfS0VZXSA9IHRydWVcblxuICAgIC8vIHdoZW4gd2UndmVbREVGQVVMVEVEX0tFWV0gYWxyZWFkeSBmb3IgYW5vdGhlciBtZXRob2QsXG4gICAgLy8gd2UgbmVlZCBhIG5ldyBmdW5jdGlvbixcbiAgICAvLyBlbHNlIHRoZSBuYW1lIHdpbGwgYmUgc2NvcGVkIGluY29ycmVjdGx5XG4gICAgY29uc3Qge29uQ2FsbCwgb25TZXQsIG9uR2V0fSA9IGJ1aWx0XG4gICAgaWYgKCFvbkdldCB8fCBvbkdldFtERUZBVUxURURfS0VZXSkge1xuICAgICAgdGhpcy5vbkdldChkZWZhdWx0T25HZXQpXG4gICAgfVxuICAgIGlmICghb25DYWxsIHx8IG9uQ2FsbFtERUZBVUxURURfS0VZXSkge1xuICAgICAgdGhpcy5vbkNhbGwoZGVmYXVsdE9uU2V0KVxuICAgIH1cbiAgICBpZiAoIW9uU2V0IHx8IG9uU2V0W0RFRkFVTFRFRF9LRVldKSB7XG4gICAgICB0aGlzLm9uU2V0KGRlZmF1bHRPblNldClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQHByb3RlY3RlZFxuICAgKiBAc2luY2UgNC4wLjAtYWxwaGEuMVxuICAgKiBAbWVtYmVyT2YgTWV0aG9kQ2hhaW5cbiAgICpcbiAgICogQHBhcmFtIHtQcmltaXRpdmV9IG5hbWVcbiAgICogQHBhcmFtIHtPYmplY3R9IHBhcmVudFxuICAgKiBAcmV0dXJuIHt2b2lkfVxuICAgKlxuICAgKiBAVE9ETyBhbGxvdyBjb25maWcgb2YgbWV0aG9kIHZhciBpbiBwbHVnaW5zIHNpbmNlIGl0IGlzIHNjb3BlZC4uLlxuICAgKiBAVE9ETyBhZGQgdG8gLm1ldGEoc2hvcnRoYW5kcylcbiAgICogQFRPRE8gcmVkdWNlIGNvbXBsZXhpdHkgaWYgcGVyZiBhbGxvd3NcbiAgICogQE5PVEUgc2NvcGluZyBoZXJlIGFkZGluZyBkZWZhdWx0IGZ1bmN0aW9ucyBoYXZlIHRvIHJlc2NvcGUgYXJndW1lbnRzXG4gICAqL1xuICBfYnVpbGQobmFtZSwgcGFyZW50KSB7XG4gICAgbGV0IG1ldGhvZFxuICAgIGxldCBleGlzdGluZ1xuICAgIGNvbnN0IGVudHJpZXMgPSAoKSA9PiB0aGlzLmVudHJpZXMoKVxuXG4gICAgLy8gY291bGQgdGVybmFyeSBgbGV0IG1ldGhvZCA9YCBoZXJlXG4gICAgaWYgKGhhc093blByb3BlcnR5KHBhcmVudCwgbmFtZSkpIHtcbiAgICAgIGV4aXN0aW5nID0gZ2V0RGVzY3JpcHRvcihwYXJlbnQsIG5hbWUpXG5cbiAgICAgIC8vIGF2b2lkIGBUeXBlRXJyb3I6IENhbm5vdCByZWRlZmluZSBwcm9wZXJ0eTpgXG4gICAgICBpZiAoaXNGYWxzZShleGlzdGluZy5jb25maWd1cmFibGUpKSB7XG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICAvLyB1c2UgZXhpc3RpbmcgcHJvcGVydHksIHdoZW4gY29uZmlndXJhYmxlXG4gICAgICBtZXRob2QgPSBleGlzdGluZy52YWx1ZVxuXG4gICAgICBpZiAoRU5WX0RFVkVMT1BNRU5UKSB7XG4gICAgICAgIG1ldGhvZC5kZWNvcmF0ZWQgPSB0cnVlXG4gICAgICB9XG5cbiAgICAgIHRoaXMub25DYWxsKG1ldGhvZCkub25TZXQobWV0aG9kKVxuICAgIH1cbiAgICBlbHNlIGlmIChwYXJlbnRbbmFtZV0pIHtcbiAgICAgIG1ldGhvZCA9IHBhcmVudFtuYW1lXVxuXG4gICAgICBpZiAoRU5WX0RFVkVMT1BNRU5UKSB7XG4gICAgICAgIG1ldGhvZC5kZWNvcmF0ZWQgPSB0cnVlXG4gICAgICB9XG5cbiAgICAgIHRoaXMub25DYWxsKG1ldGhvZCkub25TZXQobWV0aG9kKVxuICAgIH1cblxuICAgIC8vIHNjb3BlIGl0IG9uY2UgZm9yIHBsdWdpbnMgJiB0eXBlIGJ1aWxkaW5nLCB0aGVuIGdldCBpdCBhZ2FpblxuICAgIGxldCBidWlsdCA9IGVudHJpZXMoKVxuXG4gICAgdGhpcy5fZGVmYXVsdHMobmFtZSwgcGFyZW50LCBidWlsdClcblxuICAgIC8vIHBsdWdpbnMgY2FuIGFkZCBtZXRob2RzLFxuICAgIC8vIHVzZWZ1bCBhcyBwbHVnaW5zL3ByZXNldHMgJiBkZWNvcmF0b3JzIGZvciBtdWx0aS1uYW1lIGJ1aWxkaW5nXG4gICAgY29uc3QgaW5zdGFuY2VQbHVnaW5zID0gYnVpbHQucGx1Z2luc1xuICAgIGlmIChpbnN0YW5jZVBsdWdpbnMpIHtcbiAgICAgIGZvciAobGV0IHBsdWdpbiA9IDA7IHBsdWdpbiA8IGluc3RhbmNlUGx1Z2lucy5sZW5ndGg7IHBsdWdpbisrKSB7XG4gICAgICAgIGJ1aWx0ID0gZW50cmllcygpXG4gICAgICAgIGluc3RhbmNlUGx1Z2luc1twbHVnaW5dLmNhbGwodGhpcywgbmFtZSwgcGFyZW50LCBidWlsdClcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBhZnRlciBsYXN0IHBsdWdpbiBpcyBmaW5pc2hlZCwgb3IgZGVmYXVsdHNcbiAgICBidWlsdCA9IGVudHJpZXMoKVxuXG4gICAgLy8gd3JhcCBpbiBlbmNhc2luZyB3aGVuIHdlIGhhdmUgYSB2YWxpZGF0b3Igb3IgLmVuY2FzZVxuICAgIC8vIEBOT1RFOiB2YWxpZGF0b3IgcGx1Z2luIHdhcyBoZXJlLCBtb3ZlZCBpbnRvIGEgcGx1Z2luXG4gICAgaWYgKGJ1aWx0LmVuY2FzZSkge1xuICAgICAgY29uc3QgZW5jYXNlZCA9IGVuY2FzZVBsdWdpbi5jYWxsKHRoaXMsIG5hbWUsIHBhcmVudCwgYnVpbHQpKG1ldGhvZClcblxuICAgICAgaWYgKEVOVl9ERVZFTE9QTUVOVCkge1xuICAgICAgICBlbmNhc2VkLmVuY2FzZWQgPSBtZXRob2RcbiAgICAgIH1cblxuICAgICAgdGhpcy5vbkNhbGwoZW5jYXNlZCkub25TZXQoZW5jYXNlZClcbiAgICAgIG1ldGhvZCA9IGVuY2FzZWRcbiAgICAgIGJ1aWx0ID0gZW50cmllcygpXG4gICAgfVxuXG4gICAgLy8gbm90IGRlc3RydWN0dXJlZCBmb3IgYmV0dGVyIHZhcmlhYmxlIG5hbWVzXG4gICAgY29uc3Qgc2hvdWxkQWRkR2V0dGVyU2V0dGVyID0gYnVpbHQuZ2V0U2V0XG4gICAgY29uc3Qgc2hvdWxkRGVmaW5lR2V0U2V0ID0gYnVpbHQuZGVmaW5lXG4gICAgY29uc3QgZGVmYXVsdFZhbHVlID0gYnVpbHQuZGVmYXVsdFxuXG4gICAgLy8gY2FuIG9ubHkgaGF2ZSBgY2FsbGAgb3IgYGdldC9zZXRgLi4uXG4gICAgY29uc3Qge1xuICAgICAgb25HZXQsXG4gICAgICBvblNldCxcbiAgICAgIG9uQ2FsbCxcbiAgICAgIGluaXRpYWwsXG4gICAgICBiaW5kLFxuICAgICAgcmV0dXJucyxcbiAgICAgIGNhbGxSZXR1cm5zLFxuICAgICAgYWxpYXMsXG4gICAgfSA9IGJ1aWx0XG5cbiAgICAvLyBkZWZhdWx0IG1ldGhvZCwgaWYgd2UgZG8gbm90IGhhdmUgb25lIGFscmVhZHlcbiAgICBpZiAoIW1ldGhvZCkge1xuICAgICAgbWV0aG9kID0gKGFyZyA9IGRlZmF1bHRWYWx1ZSkgPT4gb25DYWxsLmNhbGwocGFyZW50LCBhcmcpXG5cbiAgICAgIGlmIChFTlZfREVWRUxPUE1FTlQpIHtcbiAgICAgICAgbWV0aG9kLmNyZWF0ZWQgPSB0cnVlXG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGJpbmQpIHtcbiAgICAgIC8vIGJpbmQgPSBiaW5kQXJndW1lbnQgfHwgcGFyZW50XG4gICAgICBtZXRob2QgPSBtZXRob2QuYmluZChiaW5kKVxuICAgIH1cbiAgICBpZiAocmV0dXJucykge1xuICAgICAgY29uc3QgcmVmID0gbWV0aG9kXG4gICAgICBtZXRob2QgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgY29uc3QgYXJncyA9IGFyZ3VtZW50b3IuYXBwbHkobnVsbCwgYXJndW1lbnRzKVxuXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBwcmVmZXItcmVzdC1wYXJhbXNcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gcmVmLmFwcGx5KHBhcmVudCwgYXJncylcblxuICAgICAgICByZXR1cm4gaXNUcnVlKGNhbGxSZXR1cm5zKVxuICAgICAgICAgID8gcmV0dXJucy5hcHBseShwYXJlbnQsIFtyZXN1bHRdLmNvbmNhdChhcmdzKSlcbiAgICAgICAgICA6IHJldHVybnNcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoIWlzVW5kZWZpbmVkKGluaXRpYWwpKSB7XG4gICAgICBwYXJlbnQuc2V0KG5hbWUsIGluaXRpYWwpXG4gICAgfVxuXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tIHN0cmlwcGVkIC0tLS0tLS0tLS0tXG5cbiAgICAvKipcbiAgICAgKiAhISEhISBAVE9ETyBwdXQgaW4gYHBsdWdpbnMucG9zdC5jYWxsYFxuICAgICAqICEhISEhIEBUT0RPIGVuc3VyZSB1bmlxdWUgbmFtZVxuICAgICAqXG4gICAgICogY2FuIGFkZCAubWV0YSBvbiB0aGVtIHRob3VnaCBmb3IgcmUtZGVjb3JhdGluZ1xuICAgICAqIC0+IGJ1dCB0aGlzIGhhcyBpc3N1ZSB3aXRoIC5nZXRzZXQgc28gbmVlZHMgdG8gYmUgb24gLm1ldGFbbmFtZV1cbiAgICAgKi9cblxuICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBkZXYgKi9cbiAgICBpZiAoRU5WX0RFVkVMT1BNRU5UKSB7XG4gICAgICBPYmplY3REZWZpbmUob25HZXQsICduYW1lJywge1xuICAgICAgICB2YWx1ZTogY2FtZWxDYXNlKGAke29uR2V0Lm5hbWV9K2dldC0ke25hbWV9YCksXG4gICAgICB9KVxuICAgICAgT2JqZWN0RGVmaW5lKG9uU2V0LCAnbmFtZScsIHtcbiAgICAgICAgdmFsdWU6IGNhbWVsQ2FzZShgJHtvblNldC5uYW1lfStzZXQtJHtuYW1lfWApLFxuICAgICAgfSlcbiAgICAgIE9iamVjdERlZmluZShvbkNhbGwsICduYW1lJywge1xuICAgICAgICB2YWx1ZTogY2FtZWxDYXNlKGAke29uQ2FsbC5uYW1lfStjYWxsLSR7bmFtZX1gKSxcbiAgICAgIH0pXG4gICAgICBPYmplY3REZWZpbmUobWV0aG9kLCAnbmFtZScsIHt2YWx1ZTogY2FtZWxDYXNlKGAke25hbWV9YCl9KVxuXG4gICAgICBpZiAoYnVpbHQudHlwZSkgbWV0aG9kLnR5cGUgPSBidWlsdC50eXBlXG4gICAgICBpZiAoaW5pdGlhbCkgbWV0aG9kLmluaXRpYWwgPSBpbml0aWFsXG4gICAgICBpZiAoYmluZCkgbWV0aG9kLmJvdW5kID0gYmluZFxuICAgICAgaWYgKHJldHVybnMpIG1ldGhvZC5yZXR1cm5zID0gcmV0dXJuc1xuICAgICAgaWYgKGFsaWFzKSBtZXRob2QuYWxpYXMgPSBhbGlhc1xuICAgICAgaWYgKGNhbGxSZXR1cm5zKSBtZXRob2QuY2FsbFJldHVybnMgPSBjYWxsUmV0dXJuc1xuICAgICAgaWYgKG9uR2V0KSBtZXRob2QuX2dldCA9IG9uR2V0XG4gICAgICBpZiAob25TZXQpIG1ldGhvZC5fc2V0ID0gb25TZXRcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuICAgICAgaWYgKG9uQ2FsbCAhPSBvbkNhbGwpIG1ldGhvZC5fY2FsbCA9IG9uQ2FsbFxuICAgIH1cblxuICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBkZXYgKi9cbiAgICBpZiAoRU5WX0RFQlVHKSB7XG4gICAgICBjb25zb2xlLmxvZyh7XG4gICAgICAgIG5hbWUsXG4gICAgICAgIGRlZmF1bHRWYWx1ZSxcbiAgICAgICAgaW5pdGlhbCxcbiAgICAgICAgcmV0dXJucyxcbiAgICAgICAgb25HZXQsXG4gICAgICAgIG9uU2V0LFxuICAgICAgICBtZXRob2Q6IG1ldGhvZC50b1N0cmluZygpLFxuICAgICAgfSlcbiAgICB9XG5cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLSA7c3RyaXBwZWQgLS0tLS0tLS0tLS0tXG5cbiAgICAvLyBAVE9ETyBXT1VMRCBBTEwgQkUgTUVUSE9ELlBPU1RcbiAgICAvLyAtLS0gY291bGQgYmUgYSBtZXRob2QgdG9vIC0tLVxuICAgIGNvbnN0IGdldHRlclNldHRlciA9IHtnZXQ6IG9uR2V0LCBzZXQ6IG9uU2V0fVxuICAgIGxldCBkZXNjcmlwdG9yID0gc2hvdWxkRGVmaW5lR2V0U2V0ID8gZ2V0dGVyU2V0dGVyIDoge3ZhbHVlOiBtZXRob2R9XG4gICAgaWYgKGV4aXN0aW5nKSBkZXNjcmlwdG9yID0gT2JqZWN0QXNzaWduKGV4aXN0aW5nLCBkZXNjcmlwdG9yKVxuXG4gICAgLy8gW1R5cGVFcnJvcjogSW52YWxpZCBwcm9wZXJ0eSBkZXNjcmlwdG9yLlxuICAgIC8vIENhbm5vdCBib3RoIHNwZWNpZnkgYWNjZXNzb3JzIGFuZCBhIHZhbHVlIG9yIHdyaXRhYmxlIGF0dHJpYnV0ZSwgIzxPYmplY3Q+XVxuICAgIGlmIChkZXNjcmlwdG9yLnZhbHVlICYmIGRlc2NyaXB0b3IuZ2V0KSB7XG4gICAgICBkZWxldGUgZGVzY3JpcHRvci52YWx1ZVxuICAgIH1cbiAgICBpZiAoIWlzVW5kZWZpbmVkKGRlc2NyaXB0b3Iud3JpdGFibGUpKSB7XG4gICAgICBkZWxldGUgZGVzY3JpcHRvci53cml0YWJsZVxuICAgIH1cblxuICAgIGNvbnN0IHRhcmdldCA9IHRoaXMuZ2V0KCd0YXJnZXQnKSB8fCBwYXJlbnRcblxuICAgIE9iamVjdERlZmluZSh0YXJnZXQsIG5hbWUsIGRlc2NyaXB0b3IpXG5cbiAgICBpZiAoc2hvdWxkQWRkR2V0dGVyU2V0dGVyKSB7XG4gICAgICBpZiAodGFyZ2V0Lm1ldGEpIHRhcmdldC5tZXRhKFNIT1JUSEFORFNfS0VZLCBuYW1lLCB