foop
Version:
interfaces that describe their intentions.
855 lines (760 loc) • 72.4 kB
JavaScript
/* 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