foop
Version:
interfaces that describe their intentions.
508 lines (466 loc) • 40.3 kB
JavaScript
/* eslint dot-notation: "OFF" */
var ENV_DEVELOPMENT = require('./deps/env/dev')
var SymbolIterator = require('./deps/symbols/iterator')
var SymbolInstance = require('./deps/symbols/instance')
var SymbolPrimitive = require('./deps/symbols/primitive')
var isPrototypeOf = require('./deps/is/prototypeOf')
var isMap = require('./deps/is/map')
var isSet = require('./deps/is/set')
var isNull = require('./deps/is/null')
var isUndefined = require('./deps/is/undefined')
var isString = require('./deps/is/string')
var isFunction = require('./deps/is/function')
var isFalse = require('./deps/is/false')
var ownPropertyIs = require('./deps/is/ownPropertyIs')
var noop = require('./deps/util/noop')
var ObjectKeys = require('./deps/util/keys')
var ObjectDefine = require('./deps/util/define')
var ignored = require('./deps/meta/ignored')
var ArrayFrom = require('./deps/util/from')
var keyValueToIterator = require('./deps/cast/keyValueToIterator')
var hasOwnPropertyFlipped = require('./deps/flipped/hasOwnPropertyFlipped')
var when = require('./deps/fp/when')
var composer = require('./compose/composer')
var pathSatisfies = require('./deps/fp/propSatisfies')
var hasStore = hasOwnPropertyFlipped('store')
var hasConstructMethod = pathSatisfies('construct', isFunction)
var hasDestructorMethod = pathSatisfies('destructor', isFunction)
// @TODO change from `||` to if else
var shouldClear = function (key, property) { return !ignored(key) &&
(isMap(property) || isSet(property) || hasStore(property)); }
// @TODO would just be `always(prop(name))`
function valueMethod(name) {
return function() {
return this[name]
}
}
// const SymbolFor = x => x // Symbol.for
// const ChainSymbol = SymbolFor('⛓')
// const ChainExtendedSymbol = SymbolFor('🍬')
// @TODO add back option to send args to parent
var ComposeChainable = function (Target, parentArgs) {
/* istanbul ignore next: dev */
if (ENV_DEVELOPMENT) {
if (!Target || !Target.prototype) {
console.log({Target: Target})
// throw new TypeError('did not have a super class / target base')
}
}
/**
* @desc Trait class that can inherit any class passed into compose, extended by ChainedMap & ChainedSet
*
* @member Chainable
* @class Chainable
* @category Chainable
* @type {Chainable}
*
* @prop {Chainable | any} parent
* @prop {string} className
*
* {@link https://github.com/iluwatar/java-design-patterns/tree/master/chain chain-pattern}
* @see {@link chain-pattern}
*
* @see ChainedMap
* @see ChainedSet
*
* @tests Chainable
* @types Chainable
*
*/
/**
* @since 0.0.1
* @memberOf Chainable
*
* @param {Chainable | any | ParentType} parent ParentType
* @constructor
*
* @example
*
* class ChainedMap extends Chainable {}
* const map = new ChainedMap()
* map.className
* //=> ChainedMap
*
*/
// var Chainable = (function(superClass) {
// console.log('@TODO!!! ADD POOLED CACHE, ADD DESTRUCTOR, DESTRUCTOR NEEDS TO CALL META')
// // Chainable,
// // console.log(superClass)
// function _Chainable(parent) {
// console.log({parent, superClass})
// if (isFunction(superClass)) {
// console.log('super is fn', {superClass, parent})
// if (isUndefined(parentArgs)) {
// superClass.call(this, parent)
// }
// else {
// superClass.call(this)
// }
// }
// // @TODO remove this if
// // if (parent)
// if (hasConstructMethod(this)) this.construct(parent)
// // .bind(this, true)
// if (!hasDestructor(this)) this.destructor = this.clear
// this.className = this.constructor.name
// this.parent = parent
// // @NOTE needed by babel & ts, buble is not-compat
// return this
// }
// Object.defineProperty(_Chainable, ChainSymbol, {value: ChainSymbol})
// // _Chainable[ChainSymbol] = ChainSymbol
// return _Chainable
// // if (isUndefined(superClass)) {
// // ChainableObject.create(Parent)
// // }
// })
// constructor(parent) {
// if (isUndefined(parentArgs)) super()
// else super(parent)
//
// // @TODO remove this
// if (parent) this.parent = parent
// if (hasConstructMethod(this)) this.construct(parent)
//
// this.className = this.constructor.name
// this.destructor = this.clear // .bind(this, true)
//
// // @NOTE needed by babel & ts, buble is not-compat
// return this
// }
var Chainable = (function (Target) {
function Chainable(parent) {
Target.call(this)
// if (hasConstructMethod(this)) this.construct(parent)
this.className = this.constructor.name
this.parent = parent
}
if ( Target ) Chainable.__proto__ = Target;
Chainable.prototype = Object.create( Target && Target.prototype );
Chainable.prototype.constructor = Chainable;
return Chainable;
}(Target));
Chainable.prototype.destructor = function() {
if (hasDestructorMethod(Target.prototype)) {
Target.prototype.destructor.call(this)
}
this.clear()
this.parent = undefined
}
// pre-initialize type && allocation?
Chainable.prototype.className = Chainable.constructor.name
// Chainable.prototype.construct = noop
// Chainable.prototype.destructor = noop
// @TODO
// https://github.com/facebook/immutable-js/blob/master/src/Hash.js
// http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
// observe on every `set` ?
Chainable.hashCode = function() {
// this.store.size
// this.className
}
/**
* @desc for ending nested chains
* @since 0.4.0
* @memberOf Chainable
*
* @return {Chainable | any}
*
* @see Chainable.parent
* @see FactoryChain
*
* @example
*
* const parent = 'eh'
* const child = newChain(parent)
* child.end()
* //=> 'eh'
*
*/
Chainable.prototype.end = valueMethod('parent')
/**
* @see fp/when
* @type {Function}
*/
Chainable.prototype.when = when
/**
* @desc clears the map,
* goes through this properties,
* calls .clear if they are instanceof Chainable or Map
*
* @memberOf Chainable
* @since 4.0.0 (moved only to Chainable, added option to clear this keys)
* @since 0.4.0 (in ChainedMap)
* @since 0.3.0 (in Chainable)
*
* @param {boolean | undefined} [clearPropertiesThatAreChainLike=true] checks properties on the object, if they are `chain-like`, clears them as well
* @return {Chainable} @chainable
*
* @see https://github.com/fliphub/flipchain/issues/2
* @see ChainedSet
* @see ChainedMap
*
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear map-clear}
* @see {@link map-clear}
*
* @example
*
* const chain = new Chain()
* chain.set('eh', 1)
* chain.entries()
* //=> {eh: 1}
* chain.clear()
* chain.entries()
* //=> {}
*
*/
Chainable.prototype.clear = function(clearPropertiesThatAreChainLike) {
var this$1 = this;
if ( clearPropertiesThatAreChainLike === void 0 ) clearPropertiesThatAreChainLike = true;
this.store.clear()
if (isFalse(clearPropertiesThatAreChainLike)) { return this }
// @TODO
// filterMap(this, (value, key) => {
// if (shouldClear(key, value)) value.clear()
// })
var keys = ObjectKeys(this)
for (var k = 0; k < keys.length; k++) {
var key = keys[k]
var property = this$1[key]
if (shouldClear(key, property)) { this$1[key].clear() }
}
return this
}
/**
* @desc calls .delete on this.store.map
* @since 0.3.0
* @memberOf Chainable
*
* @param {Primitive} key on a Map: key referencing the value. on a Set: the index
* @return {Chainable}
*
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete mozilla-map-delete}
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete mozilla-set-delete}
* @see {@link mozilla-map-delete}
* @see {@link mozilla-set-delete}
* @see ChainedSet
* @see ChainedMap
*
* @example
*
* const chain = new Chain()
* chain.set('eh', 1)
* chain.get('eh')
* //=> 1
*
* chain.delete('eh', 1)
* chain.get('eh')
* //=> undefined
*
*/
Chainable.prototype['delete'] = function(key) {
this.store.delete(key)
return this
}
/**
* @desc checks whether the store has a value for a given key
* @memberOf Chainable
* @since 0.3.0
*
* @param {any} keyOrValue key when Map, value when Set
* @return {boolean} `this.store.has(keyOrValue)`
*
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has mozilla-map-has}
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has mozilla-set-has}
* @see {@link mozilla-map-has}
* @see {@link mozilla-set-has}
*
* @example
*
* const chain = new Chain()
* chain.set('eh', 1).has('eh')
* //=> true
* chain.has('canada')
* //=> false
*
*/
Chainable.prototype.has = function(keyOrValue) {
return this.store.has(keyOrValue)
}
/**
* @desc spreads the entries from ChainedMap.store.values
* allocates a new array, adds the values from the iterator
*
* @memberOf Chainable
* @since 0.4.0
*
* @return {Array<any>} toArr(this.store.values())
*
* @NOTE look at Chainable.constructor to ensure not to use `new Array...`
* @NOTE moved from ChainedMap and ChainedSet to Chainable @2.0.2
* @NOTE this was [...] & Array.from(this.store.values())
*
* {@link https://kangax.github.io/compat-table/es6/#test-Array_static_methods compat-array-static-methods}
* {@link https://stackoverflow.com/questions/20069828/how-to-convert-set-to-array set-to-array}
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values mozilla-map-values}
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/values mozilla-set-values}
*
* @see {@link mozilla-map-values}
* @see {@link mozilla-set-values}
* @see {@link compat-array-static-methods}
* @see {@link set-to-array}
*
*
* @example
*
* const chain = new Chain()
* chain.set('eh', 1)
* chain.values()
* //=> [1]
*
*/
Chainable.prototype.values = function() {
return ArrayFrom(this.store.values())
}
// --- symbols ---
/**
* @desc Iterator for looping values in the store
*
* @memberOf Chainable
* @since 0.5.0
* @version 5.0.0 <- uses.keys > keys(entries())
*
* @type {generator}
* @return {Object} {value: undefined | any, done: true | false}
*
* @NOTE assigned to a variable so buble ignores it
* @NOTE both Map & Set collections iterate with `[key, val]`
*
* @see https://www.typescriptlang.org/docs/handbook/iterators-and-generators.html
* @see http://exploringjs.com/es6/ch_iteration.html#_maps-1
* @see https://github.com/sindresorhus/quick-lru/blob/master/index.js
* @see https://stackoverflow.com/questions/36976832/what-is-the-meaning-of-symbol-iterator-in-this-context
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator
* @see this.store
*
* @tests iteration
*
* @example
*
* const chain = new Chain().set('eh', 1)
* for (var [key, val] of chain) console.log({[key]: val})
* //=> {eh: 1}
*
* @example
*
* *[Symbol.iterator](): void { for (const item of this.store) yield item }
*
* @example
*
* const {ChainedSet} = require('chain-able')
* const set = new ChainedSet()
* set.add('eh')
*
* for (const arr of set) {
* const [key, val] = arr
*
* key //=> 0
* val //=> 'eh'
* arr.length //=> 2
* }
*
*/
Chainable.prototype[SymbolIterator] = function() {
return keyValueToIterator(this.keys(), this.values(), this.store.size)
}
/**
* @desc symbol method for toString, toJSON, toNumber
* @memberOf Chainable
* @since 1.0.2
* @version 2
*
* @param {string} hint enum[default, string, number]
* @return {Primitive}
*
* {@link http://2ality.com/2015/09/well-known-symbols-es6.html#default-tostring-tags well-known-symbols-es6}
* @see {@link well-known-symbols-es6}
*
* @example
*
* const chain = new Chain()
* chain.toNumber = () => 1
* +chain;
* //=> 1
* chain + 1
* //=>
*
* @example
*
* const chain = new Chain()
* chain.toString = () => 'eh'
* chain + ''
* //=> 'eh'
*
*/
Chainable.prototype[SymbolPrimitive] = function(hint) {
/* prettier-ignore */
/**
* hint === 'number'
* `s`tring is 115
* `n`umber is 110
* 110 & 4 = 1
* 115 & 4 = 0
*
* if (hint === 'string' && this.toJSON) return this.toJSON()
* else if (hint === 'number' && this.toNumber) return this.toNumber()
*/
if (hint === 'number' && this.toNumber) { return this.toNumber() }
// hint === 'string'
if (this.toJSON) { return this.toJSON() }
// hint === 'default'
return this.toString()
}
/**
* @memberOf Chainable
* @name length
* @method length
* @readonly
* @since 0.5.0
* @see ChainedMap.store
* @return {number}
* @example for (var i = 0; i < chain.length; i++)
*/
ObjectDefine(Chainable.prototype, 'length', {
enumerable: false,
get: function get() {
return this.store.size
},
})
ObjectDefine(Chainable.prototype, SymbolInstance, {
enumerable: false,
value: function (instance) { return instance &&
(isPrototypeOf(Chainable.prototype, instance) || hasStore(instance)); },
})
// @TODO to wrap in toFunction but keep prototype
// return function(parent) {
// const instance = new Chainable(parent)
// // console.log({instance}, instance.end)
// return instance
// }
return Chainable
}
/**
* @since 3.0.0
* @func
* @example
*
* class Target {}
* const TargetChain = Chainable.compose(Target)
* const chain = new TargetChain()
* chain instanceof Target
* //=> true
*
*/
var c = composer(ComposeChainable, noop)
module.exports = c
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2hhaW5hYmxlLmpzIiwic291cmNlcyI6WyJDaGFpbmFibGUuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50IGRvdC1ub3RhdGlvbjogXCJPRkZcIiAqL1xuXG5jb25zdCBFTlZfREVWRUxPUE1FTlQgPSByZXF1aXJlKCcuL2RlcHMvZW52L2RldicpXG5jb25zdCBTeW1ib2xJdGVyYXRvciA9IHJlcXVpcmUoJy4vZGVwcy9zeW1ib2xzL2l0ZXJhdG9yJylcbmNvbnN0IFN5bWJvbEluc3RhbmNlID0gcmVxdWlyZSgnLi9kZXBzL3N5bWJvbHMvaW5zdGFuY2UnKVxuY29uc3QgU3ltYm9sUHJpbWl0aXZlID0gcmVxdWlyZSgnLi9kZXBzL3N5bWJvbHMvcHJpbWl0aXZlJylcbmNvbnN0IGlzUHJvdG90eXBlT2YgPSByZXF1aXJlKCcuL2RlcHMvaXMvcHJvdG90eXBlT2YnKVxuY29uc3QgaXNNYXAgPSByZXF1aXJlKCcuL2RlcHMvaXMvbWFwJylcbmNvbnN0IGlzU2V0ID0gcmVxdWlyZSgnLi9kZXBzL2lzL3NldCcpXG5jb25zdCBpc051bGwgPSByZXF1aXJlKCcuL2RlcHMvaXMvbnVsbCcpXG5jb25zdCBpc1VuZGVmaW5lZCA9IHJlcXVpcmUoJy4vZGVwcy9pcy91bmRlZmluZWQnKVxuY29uc3QgaXNTdHJpbmcgPSByZXF1aXJlKCcuL2RlcHMvaXMvc3RyaW5nJylcbmNvbnN0IGlzRnVuY3Rpb24gPSByZXF1aXJlKCcuL2RlcHMvaXMvZnVuY3Rpb24nKVxuY29uc3QgaXNGYWxzZSA9IHJlcXVpcmUoJy4vZGVwcy9pcy9mYWxzZScpXG5jb25zdCBvd25Qcm9wZXJ0eUlzID0gcmVxdWlyZSgnLi9kZXBzL2lzL293blByb3BlcnR5SXMnKVxuY29uc3Qgbm9vcCA9IHJlcXVpcmUoJy4vZGVwcy91dGlsL25vb3AnKVxuY29uc3QgT2JqZWN0S2V5cyA9IHJlcXVpcmUoJy4vZGVwcy91dGlsL2tleXMnKVxuY29uc3QgT2JqZWN0RGVmaW5lID0gcmVxdWlyZSgnLi9kZXBzL3V0aWwvZGVmaW5lJylcbmNvbnN0IGlnbm9yZWQgPSByZXF1aXJlKCcuL2RlcHMvbWV0YS9pZ25vcmVkJylcbmNvbnN0IEFycmF5RnJvbSA9IHJlcXVpcmUoJy4vZGVwcy91dGlsL2Zyb20nKVxuY29uc3Qga2V5VmFsdWVUb0l0ZXJhdG9yID0gcmVxdWlyZSgnLi9kZXBzL2Nhc3Qva2V5VmFsdWVUb0l0ZXJhdG9yJylcbmNvbnN0IGhhc093blByb3BlcnR5RmxpcHBlZCA9IHJlcXVpcmUoJy4vZGVwcy9mbGlwcGVkL2hhc093blByb3BlcnR5RmxpcHBlZCcpXG5jb25zdCB3aGVuID0gcmVxdWlyZSgnLi9kZXBzL2ZwL3doZW4nKVxuY29uc3QgY29tcG9zZXIgPSByZXF1aXJlKCcuL2NvbXBvc2UvY29tcG9zZXInKVxuY29uc3QgcGF0aFNhdGlzZmllcyA9IHJlcXVpcmUoJy4vZGVwcy9mcC9wcm9wU2F0aXNmaWVzJylcblxuY29uc3QgaGFzU3RvcmUgPSBoYXNPd25Qcm9wZXJ0eUZsaXBwZWQoJ3N0b3JlJylcbmNvbnN0IGhhc0NvbnN0cnVjdE1ldGhvZCA9IHBhdGhTYXRpc2ZpZXMoJ2NvbnN0cnVjdCcsIGlzRnVuY3Rpb24pXG5jb25zdCBoYXNEZXN0cnVjdG9yTWV0aG9kID0gcGF0aFNhdGlzZmllcygnZGVzdHJ1Y3RvcicsIGlzRnVuY3Rpb24pXG5cbi8vIEBUT0RPIGNoYW5nZSBmcm9tIGB8fGAgdG8gaWYgZWxzZVxuY29uc3Qgc2hvdWxkQ2xlYXIgPSAoa2V5LCBwcm9wZXJ0eSkgPT5cbiAgIWlnbm9yZWQoa2V5KSAmJlxuICAoaXNNYXAocHJvcGVydHkpIHx8IGlzU2V0KHByb3BlcnR5KSB8fCBoYXNTdG9yZShwcm9wZXJ0eSkpXG5cblxuLy8gQFRPRE8gd291bGQganVzdCBiZSBgYWx3YXlzKHByb3AobmFtZSkpYFxuZnVuY3Rpb24gdmFsdWVNZXRob2QobmFtZSkge1xuICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXNbbmFtZV1cbiAgfVxufVxuXG4vLyBjb25zdCBTeW1ib2xGb3IgPSB4ID0+IHggLy8gU3ltYm9sLmZvclxuLy8gY29uc3QgQ2hhaW5TeW1ib2wgPSBTeW1ib2xGb3IoJ+KbkycpXG4vLyBjb25zdCBDaGFpbkV4dGVuZGVkU3ltYm9sID0gU3ltYm9sRm9yKCfwn42sJylcblxuLy8gQFRPRE8gYWRkIGJhY2sgb3B0aW9uIHRvIHNlbmQgYXJncyB0byBwYXJlbnRcbmNvbnN0IENvbXBvc2VDaGFpbmFibGUgPSAoVGFyZ2V0LCBwYXJlbnRBcmdzKSA9PiB7XG4gIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBkZXYgKi9cbiAgaWYgKEVOVl9ERVZFTE9QTUVOVCkge1xuICAgIGlmICghVGFyZ2V0IHx8ICFUYXJnZXQucHJvdG90eXBlKSB7XG4gICAgICBjb25zb2xlLmxvZyh7VGFyZ2V0fSlcbiAgICAgIC8vIHRocm93IG5ldyBUeXBlRXJyb3IoJ2RpZCBub3QgaGF2ZSBhIHN1cGVyIGNsYXNzIC8gdGFyZ2V0IGJhc2UnKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzYyBUcmFpdCBjbGFzcyB0aGF0IGNhbiBpbmhlcml0IGFueSBjbGFzcyBwYXNzZWQgaW50byBjb21wb3NlLCBleHRlbmRlZCBieSBDaGFpbmVkTWFwICYgQ2hhaW5lZFNldFxuICAgKlxuICAgKiBAbWVtYmVyIENoYWluYWJsZVxuICAgKiBAY2xhc3MgQ2hhaW5hYmxlXG4gICAqIEBjYXRlZ29yeSBDaGFpbmFibGVcbiAgICogQHR5cGUge0NoYWluYWJsZX1cbiAgICpcbiAgICogQHByb3Age0NoYWluYWJsZSB8IGFueX0gcGFyZW50XG4gICAqIEBwcm9wIHtzdHJpbmd9IGNsYXNzTmFtZVxuICAgKlxuICAgKiB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL2lsdXdhdGFyL2phdmEtZGVzaWduLXBhdHRlcm5zL3RyZWUvbWFzdGVyL2NoYWluIGNoYWluLXBhdHRlcm59XG4gICAqIEBzZWUge0BsaW5rIGNoYWluLXBhdHRlcm59XG4gICAqXG4gICAqIEBzZWUgQ2hhaW5lZE1hcFxuICAgKiBAc2VlIENoYWluZWRTZXRcbiAgICpcbiAgICogQHRlc3RzIENoYWluYWJsZVxuICAgKiBAdHlwZXMgQ2hhaW5hYmxlXG4gICAqXG4gICAqL1xuXG5cbiAgLyoqXG4gICAqIEBzaW5jZSAwLjAuMVxuICAgKiBAbWVtYmVyT2YgQ2hhaW5hYmxlXG4gICAqXG4gICAqIEBwYXJhbSB7Q2hhaW5hYmxlIHwgYW55IHwgUGFyZW50VHlwZX0gcGFyZW50IFBhcmVudFR5cGVcbiAgICogQGNvbnN0cnVjdG9yXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgIGNsYXNzIENoYWluZWRNYXAgZXh0ZW5kcyBDaGFpbmFibGUge31cbiAgICogICAgY29uc3QgbWFwID0gbmV3IENoYWluZWRNYXAoKVxuICAgKiAgICBtYXAuY2xhc3NOYW1lXG4gICAqICAgIC8vPT4gQ2hhaW5lZE1hcFxuICAgKlxuICAgKi9cblxuICAvLyB2YXIgQ2hhaW5hYmxlID0gKGZ1bmN0aW9uKHN1cGVyQ2xhc3MpIHtcbiAgLy8gICBjb25zb2xlLmxvZygnQFRPRE8hISEgQUREIFBPT0xFRCBDQUNIRSwgQUREIERFU1RSVUNUT1IsIERFU1RSVUNUT1IgTkVFRFMgVE8gQ0FMTCBNRVRBJylcbiAgLy8gICAvLyBDaGFpbmFibGUsXG4gIC8vICAgLy8gY29uc29sZS5sb2coc3VwZXJDbGFzcylcbiAgLy8gICBmdW5jdGlvbiBfQ2hhaW5hYmxlKHBhcmVudCkge1xuICAvLyAgICAgY29uc29sZS5sb2coe3BhcmVudCwgc3VwZXJDbGFzc30pXG4gIC8vICAgICBpZiAoaXNGdW5jdGlvbihzdXBlckNsYXNzKSkge1xuICAvLyAgICAgICBjb25zb2xlLmxvZygnc3VwZXIgaXMgZm4nLCB7c3VwZXJDbGFzcywgcGFyZW50fSlcbiAgLy8gICAgICAgaWYgKGlzVW5kZWZpbmVkKHBhcmVudEFyZ3MpKSB7XG4gIC8vICAgICAgICAgc3VwZXJDbGFzcy5jYWxsKHRoaXMsIHBhcmVudClcbiAgLy8gICAgICAgfVxuICAvLyAgICAgICBlbHNlIHtcbiAgLy8gICAgICAgICBzdXBlckNsYXNzLmNhbGwodGhpcylcbiAgLy8gICAgICAgfVxuICAvLyAgICAgfVxuXG4gIC8vICAgICAvLyBAVE9ETyByZW1vdmUgdGhpcyBpZlxuICAvLyAgICAgLy8gaWYgKHBhcmVudClcbiAgLy8gICAgIGlmIChoYXNDb25zdHJ1Y3RNZXRob2QodGhpcykpIHRoaXMuY29uc3RydWN0KHBhcmVudClcbiAgLy8gICAgIC8vIC5iaW5kKHRoaXMsIHRydWUpXG4gIC8vICAgICBpZiAoIWhhc0Rlc3RydWN0b3IodGhpcykpIHRoaXMuZGVzdHJ1Y3RvciA9IHRoaXMuY2xlYXJcbiAgLy8gICAgIHRoaXMuY2xhc3NOYW1lID0gdGhpcy5jb25zdHJ1Y3Rvci5uYW1lXG4gIC8vICAgICB0aGlzLnBhcmVudCA9IHBhcmVudFxuICAvLyAgICAgLy8gQE5PVEUgbmVlZGVkIGJ5IGJhYmVsICYgdHMsIGJ1YmxlIGlzIG5vdC1jb21wYXRcbiAgLy8gICAgIHJldHVybiB0aGlzXG4gIC8vICAgfVxuICAvLyAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShfQ2hhaW5hYmxlLCBDaGFpblN5bWJvbCwge3ZhbHVlOiBDaGFpblN5bWJvbH0pXG4gIC8vICAgLy8gX0NoYWluYWJsZVtDaGFpblN5bWJvbF0gPSBDaGFpblN5bWJvbFxuICAvLyAgIHJldHVybiBfQ2hhaW5hYmxlXG4gIC8vICAgLy8gaWYgKGlzVW5kZWZpbmVkKHN1cGVyQ2xhc3MpKSB7XG4gIC8vICAgLy8gICBDaGFpbmFibGVPYmplY3QuY3JlYXRlKFBhcmVudClcbiAgLy8gICAvLyB9XG4gIC8vIH0pXG5cbiAgLy8gY29uc3RydWN0b3IocGFyZW50KSB7XG4gIC8vICAgaWYgKGlzVW5kZWZpbmVkKHBhcmVudEFyZ3MpKSBzdXBlcigpXG4gIC8vICAgZWxzZSBzdXBlcihwYXJlbnQpXG4gIC8vXG4gIC8vICAgLy8gQFRPRE8gcmVtb3ZlIHRoaXNcbiAgLy8gICBpZiAocGFyZW50KSB0aGlzLnBhcmVudCA9IHBhcmVudFxuICAvLyAgIGlmIChoYXNDb25zdHJ1Y3RNZXRob2QodGhpcykpIHRoaXMuY29uc3RydWN0KHBhcmVudClcbiAgLy9cbiAgLy8gICB0aGlzLmNsYXNzTmFtZSA9IHRoaXMuY29uc3RydWN0b3IubmFtZVxuICAvLyAgIHRoaXMuZGVzdHJ1Y3RvciA9IHRoaXMuY2xlYXIgLy8gLmJpbmQodGhpcywgdHJ1ZSlcbiAgLy9cbiAgLy8gICAvLyBATk9URSBuZWVkZWQgYnkgYmFiZWwgJiB0cywgYnVibGUgaXMgbm90LWNvbXBhdFxuICAvLyAgIHJldHVybiB0aGlzXG4gIC8vIH1cblxuICBjbGFzcyBDaGFpbmFibGUgZXh0ZW5kcyBUYXJnZXQge1xuICAgIGNvbnN0cnVjdG9yKHBhcmVudCkge1xuICAgICAgc3VwZXIoKVxuXG4gICAgICAvLyBpZiAoaGFzQ29uc3RydWN0TWV0aG9kKHRoaXMpKSB0aGlzLmNvbnN0cnVjdChwYXJlbnQpXG4gICAgICB0aGlzLmNsYXNzTmFtZSA9IHRoaXMuY29uc3RydWN0b3IubmFtZVxuICAgICAgdGhpcy5wYXJlbnQgPSBwYXJlbnRcbiAgICB9XG4gIH1cblxuICBDaGFpbmFibGUucHJvdG90eXBlLmRlc3RydWN0b3IgPSBmdW5jdGlvbigpIHtcbiAgICBpZiAoaGFzRGVzdHJ1Y3Rvck1ldGhvZChUYXJnZXQucHJvdG90eXBlKSkge1xuICAgICAgVGFyZ2V0LnByb3RvdHlwZS5kZXN0cnVjdG9yLmNhbGwodGhpcylcbiAgICB9XG4gICAgdGhpcy5jbGVhcigpXG4gICAgdGhpcy5wYXJlbnQgPSB1bmRlZmluZWRcbiAgfVxuXG4gIC8vIHByZS1pbml0aWFsaXplIHR5cGUgJiYgYWxsb2NhdGlvbj9cbiAgQ2hhaW5hYmxlLnByb3RvdHlwZS5jbGFzc05hbWUgPSBDaGFpbmFibGUuY29uc3RydWN0b3IubmFtZVxuICAvLyBDaGFpbmFibGUucHJvdG90eXBlLmNvbnN0cnVjdCA9IG5vb3BcbiAgLy8gQ2hhaW5hYmxlLnByb3RvdHlwZS5kZXN0cnVjdG9yID0gbm9vcFxuXG4gIC8vIEBUT0RPXG4gIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9mYWNlYm9vay9pbW11dGFibGUtanMvYmxvYi9tYXN0ZXIvc3JjL0hhc2guanNcbiAgLy8gaHR0cDovL3dlcnhsdGQuY29tL3dwLzIwMTAvMDUvMTMvamF2YXNjcmlwdC1pbXBsZW1lbnRhdGlvbi1vZi1qYXZhcy1zdHJpbmctaGFzaGNvZGUtbWV0aG9kL1xuICAvLyBvYnNlcnZlIG9uIGV2ZXJ5IGBzZXRgID9cbiAgQ2hhaW5hYmxlLmhhc2hDb2RlID0gZnVuY3Rpb24oKSB7XG4gICAgLy8gdGhpcy5zdG9yZS5zaXplXG4gICAgLy8gdGhpcy5jbGFzc05hbWVcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzYyBmb3IgZW5kaW5nIG5lc3RlZCBjaGFpbnNcbiAgICogQHNpbmNlIDAuNC4wXG4gICAqIEBtZW1iZXJPZiBDaGFpbmFibGVcbiAgICpcbiAgICogQHJldHVybiB7Q2hhaW5hYmxlIHwgYW55fVxuICAgKlxuICAgKiBAc2VlIENoYWluYWJsZS5wYXJlbnRcbiAgICogQHNlZSBGYWN0b3J5Q2hhaW5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgY29uc3QgcGFyZW50ID0gJ2VoJ1xuICAgKiAgICBjb25zdCBjaGlsZCA9IG5ld0NoYWluKHBhcmVudClcbiAgICogICAgY2hpbGQuZW5kKClcbiAgICogICAgLy89PiAnZWgnXG4gICAqXG4gICAqL1xuICBDaGFpbmFibGUucHJvdG90eXBlLmVuZCA9IHZhbHVlTWV0aG9kKCdwYXJlbnQnKVxuXG4gIC8qKlxuICAgKiBAc2VlIGZwL3doZW5cbiAgICogQHR5cGUge0Z1bmN0aW9ufVxuICAgKi9cbiAgQ2hhaW5hYmxlLnByb3RvdHlwZS53aGVuID0gd2hlblxuXG4gIC8qKlxuICAgKiBAZGVzYyBjbGVhcnMgdGhlIG1hcCxcbiAgICogICAgICAgZ29lcyB0aHJvdWdoIHRoaXMgcHJvcGVydGllcyxcbiAgICogICAgICAgY2FsbHMgLmNsZWFyIGlmIHRoZXkgYXJlIGluc3RhbmNlb2YgQ2hhaW5hYmxlIG9yIE1hcFxuICAgKlxuICAgKiBAbWVtYmVyT2YgQ2hhaW5hYmxlXG4gICAqIEBzaW5jZSA0LjAuMCAobW92ZWQgb25seSB0byBDaGFpbmFibGUsIGFkZGVkIG9wdGlvbiB0byBjbGVhciB0aGlzIGtleXMpXG4gICAqIEBzaW5jZSAwLjQuMCAoaW4gQ2hhaW5lZE1hcClcbiAgICogQHNpbmNlIDAuMy4wIChpbiBDaGFpbmFibGUpXG4gICAqXG4gICAqIEBwYXJhbSB7Ym9vbGVhbiB8IHVuZGVmaW5lZH0gW2NsZWFyUHJvcGVydGllc1RoYXRBcmVDaGFpbkxpa2U9dHJ1ZV0gY2hlY2tzIHByb3BlcnRpZXMgb24gdGhlIG9iamVjdCwgaWYgdGhleSBhcmUgYGNoYWluLWxpa2VgLCBjbGVhcnMgdGhlbSBhcyB3ZWxsXG4gICAqIEByZXR1cm4ge0NoYWluYWJsZX0gQGNoYWluYWJsZVxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9mbGlwaHViL2ZsaXBjaGFpbi9pc3N1ZXMvMlxuICAgKiBAc2VlIENoYWluZWRTZXRcbiAgICogQHNlZSBDaGFpbmVkTWFwXG4gICAqXG4gICAqIHtAbGluayBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9NYXAvY2xlYXIgbWFwLWNsZWFyfVxuICAgKiBAc2VlIHtAbGluayBtYXAtY2xlYXJ9XG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgIGNvbnN0IGNoYWluID0gbmV3IENoYWluKClcbiAgICogICAgY2hhaW4uc2V0KCdlaCcsIDEpXG4gICAqICAgIGNoYWluLmVudHJpZXMoKVxuICAgKiAgICAvLz0+IHtlaDogMX1cbiAgICogICAgY2hhaW4uY2xlYXIoKVxuICAgKiAgICBjaGFpbi5lbnRyaWVzKClcbiAgICogICAgLy89PiB7fVxuICAgKlxuICAgKi9cbiAgQ2hhaW5hYmxlLnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uKGNsZWFyUHJvcGVydGllc1RoYXRBcmVDaGFpbkxpa2UgPSB0cnVlKSB7XG4gICAgdGhpcy5zdG9yZS5jbGVhcigpXG5cbiAgICBpZiAoaXNGYWxzZShjbGVhclByb3BlcnRpZXNUaGF0QXJlQ2hhaW5MaWtlKSkgcmV0dXJuIHRoaXNcblxuICAgIC8vIEBUT0RPXG4gICAgLy8gZmlsdGVyTWFwKHRoaXMsICh2YWx1ZSwga2V5KSA9PiB7XG4gICAgLy8gICBpZiAoc2hvdWxkQ2xlYXIoa2V5LCB2YWx1ZSkpIHZhbHVlLmNsZWFyKClcbiAgICAvLyB9KVxuXG4gICAgY29uc3Qga2V5cyA9IE9iamVjdEtleXModGhpcylcbiAgICBmb3IgKGxldCBrID0gMDsgayA8IGtleXMubGVuZ3RoOyBrKyspIHtcbiAgICAgIGNvbnN0IGtleSA9IGtleXNba11cbiAgICAgIGNvbnN0IHByb3BlcnR5ID0gdGhpc1trZXldXG4gICAgICBpZiAoc2hvdWxkQ2xlYXIoa2V5LCBwcm9wZXJ0eSkpIHRoaXNba2V5XS5jbGVhcigpXG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzYyBjYWxscyAuZGVsZXRlIG9uIHRoaXMuc3RvcmUubWFwXG4gICAqIEBzaW5jZSAwLjMuMFxuICAgKiBAbWVtYmVyT2YgQ2hhaW5hYmxlXG4gICAqXG4gICAqIEBwYXJhbSB7UHJpbWl0aXZlfSBrZXkgb24gYSBNYXA6IGtleSByZWZlcmVuY2luZyB0aGUgdmFsdWUuIG9uIGEgU2V0OiB0aGUgaW5kZXhcbiAgICogQHJldHVybiB7Q2hhaW5hYmxlfVxuICAgKlxuICAgKiB7QGxpbmsgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvTWFwL2RlbGV0ZSBtb3ppbGxhLW1hcC1kZWxldGV9XG4gICAqIHtAbGluayBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9TZXQvZGVsZXRlIG1vemlsbGEtc2V0LWRlbGV0ZX1cbiAgICogQHNlZSB7QGxpbmsgbW96aWxsYS1tYXAtZGVsZXRlfVxuICAgKiBAc2VlIHtAbGluayBtb3ppbGxhLXNldC1kZWxldGV9XG4gICAqIEBzZWUgQ2hhaW5lZFNldFxuICAgKiBAc2VlIENoYWluZWRNYXBcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgY29uc3QgY2hhaW4gPSBuZXcgQ2hhaW4oKVxuICAgKiAgICBjaGFpbi5zZXQoJ2VoJywgMSlcbiAgICogICAgY2hhaW4uZ2V0KCdlaCcpXG4gICAqICAgIC8vPT4gMVxuICAgKlxuICAgKiAgICBjaGFpbi5kZWxldGUoJ2VoJywgMSlcbiAgICogICAgY2hhaW4uZ2V0KCdlaCcpXG4gICAqICAgIC8vPT4gdW5kZWZpbmVkXG4gICAqXG4gICAqL1xuICBDaGFpbmFibGUucHJvdG90eXBlWydkZWxldGUnXSA9IGZ1bmN0aW9uKGtleSkge1xuICAgIHRoaXMuc3RvcmUuZGVsZXRlKGtleSlcbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjIGNoZWNrcyB3aGV0aGVyIHRoZSBzdG9yZSBoYXMgYSB2YWx1ZSBmb3IgYSBnaXZlbiBrZXlcbiAgICogQG1lbWJlck9mIENoYWluYWJsZVxuICAgKiBAc2luY2UgMC4zLjBcbiAgICpcbiAgICogQHBhcmFtIHthbnl9IGtleU9yVmFsdWUga2V5IHdoZW4gTWFwLCB2YWx1ZSB3aGVuIFNldFxuICAgKiBAcmV0dXJuIHtib29sZWFufSBgdGhpcy5zdG9yZS5oYXMoa2V5T3JWYWx1ZSlgXG4gICAqXG4gICAqIHtAbGluayBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9NYXAvaGFzIG1vemlsbGEtbWFwLWhhc31cbiAgICoge0BsaW5rIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL1NldC9oYXMgbW96aWxsYS1zZXQtaGFzfVxuICAgKiBAc2VlIHtAbGluayBtb3ppbGxhLW1hcC1oYXN9XG4gICAqIEBzZWUge0BsaW5rIG1vemlsbGEtc2V0LWhhc31cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICBjb25zdCBjaGFpbiA9IG5ldyBDaGFpbigpXG4gICAqICAgY2hhaW4uc2V0KCdlaCcsIDEpLmhhcygnZWgnKVxuICAgKiAgIC8vPT4gdHJ1ZVxuICAgKiAgIGNoYWluLmhhcygnY2FuYWRhJylcbiAgICogICAvLz0+IGZhbHNlXG4gICAqXG4gICAqL1xuICBDaGFpbmFibGUucHJvdG90eXBlLmhhcyA9IGZ1bmN0aW9uKGtleU9yVmFsdWUpIHtcbiAgICByZXR1cm4gdGhpcy5zdG9yZS5oYXMoa2V5T3JWYWx1ZSlcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzYyBzcHJlYWRzIHRoZSBlbnRyaWVzIGZyb20gQ2hhaW5lZE1hcC5zdG9yZS52YWx1ZXNcbiAgICogICAgICAgYWxsb2NhdGVzIGEgbmV3IGFycmF5LCBhZGRzIHRoZSB2YWx1ZXMgZnJvbSB0aGUgaXRlcmF0b3JcbiAgICpcbiAgICogQG1lbWJlck9mIENoYWluYWJsZVxuICAgKiBAc2luY2UgMC40LjBcbiAgICpcbiAgICogQHJldHVybiB7QXJyYXk8YW55Pn0gdG9BcnIodGhpcy5zdG9yZS52YWx1ZXMoKSlcbiAgICpcbiAgICogQE5PVEUgbG9vayBhdCBDaGFpbmFibGUuY29uc3RydWN0b3IgdG8gZW5zdXJlIG5vdCB0byB1c2UgYG5ldyBBcnJheS4uLmBcbiAgICogQE5PVEUgbW92ZWQgZnJvbSBDaGFpbmVkTWFwIGFuZCBDaGFpbmVkU2V0IHRvIENoYWluYWJsZSBAMi4wLjJcbiAgICogQE5PVEUgdGhpcyB3YXMgWy4uLl0gJiBBcnJheS5mcm9tKHRoaXMuc3RvcmUudmFsdWVzKCkpXG4gICAqXG4gICAqIHtAbGluayBodHRwczovL2thbmdheC5naXRodWIuaW8vY29tcGF0LXRhYmxlL2VzNi8jdGVzdC1BcnJheV9zdGF0aWNfbWV0aG9kcyBjb21wYXQtYXJyYXktc3RhdGljLW1ldGhvZHN9XG4gICAqIHtAbGluayBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8yMDA2OTgyOC9ob3ctdG8tY29udmVydC1zZXQtdG8tYXJyYXkgc2V0LXRvLWFycmF5fVxuICAgKiB7QGxpbmsgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvTWFwL3ZhbHVlcyBtb3ppbGxhLW1hcC12YWx1ZXN9XG4gICAqIHtAbGluayBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9TZXQvdmFsdWVzIG1vemlsbGEtc2V0LXZhbHVlc31cbiAgICpcbiAgICogQHNlZSB7QGxpbmsgbW96aWxsYS1tYXAtdmFsdWVzfVxuICAgKiBAc2VlIHtAbGluayBtb3ppbGxhLXNldC12YWx1ZXN9XG4gICAqIEBzZWUge0BsaW5rIGNvbXBhdC1hcnJheS1zdGF0aWMtbWV0aG9kc31cbiAgICogQHNlZSB7QGxpbmsgc2V0LXRvLWFycmF5fVxuICAgKlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgY29uc3QgY2hhaW4gPSBuZXcgQ2hhaW4oKVxuICAgKiAgY2hhaW4uc2V0KCdlaCcsIDEpXG4gICAqICBjaGFpbi52YWx1ZXMoKVxuICAgKiAgLy89PiBbMV1cbiAgICpcbiAgICovXG4gIENoYWluYWJsZS5wcm90b3R5cGUudmFsdWVzID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIEFycmF5RnJvbSh0aGlzLnN0b3JlLnZhbHVlcygpKVxuICB9XG5cbiAgLy8gLS0tIHN5bWJvbHMgLS0tXG5cbiAgLyoqXG4gICAqIEBkZXNjIEl0ZXJhdG9yIGZvciBsb29waW5nIHZhbHVlcyBpbiB0aGUgc3RvcmVcbiAgICpcbiAgICogQG1lbWJlck9mIENoYWluYWJsZVxuICAgKiBAc2luY2UgMC41LjBcbiAgICogQHZlcnNpb24gNS4wLjAgPC0gdXNlcy5rZXlzID4ga2V5cyhlbnRyaWVzKCkpXG4gICAqXG4gICAqIEB0eXBlIHtnZW5lcmF0b3J9XG4gICAqIEByZXR1cm4ge09iamVjdH0ge3ZhbHVlOiB1bmRlZmluZWQgfCBhbnksIGRvbmU6IHRydWUgfCBmYWxzZX1cbiAgICpcbiAgICogQE5PVEUgYXNzaWduZWQgdG8gYSB2YXJpYWJsZSBzbyBidWJsZSBpZ25vcmVzIGl0XG4gICAqIEBOT1RFIGJvdGggTWFwICYgU2V0IGNvbGxlY3Rpb25zIGl0ZXJhdGUgd2l0aCBgW2tleSwgdmFsXWBcbiAgICpcbiAgICogQHNlZSBodHRwczovL3d3dy50eXBlc2NyaXB0bGFuZy5vcmcvZG9jcy9oYW5kYm9vay9pdGVyYXRvcnMtYW5kLWdlbmVyYXRvcnMuaHRtbFxuICAgKiBAc2VlIGh0dHA6Ly9leHBsb3Jpbmdqcy5jb20vZXM2L2NoX2l0ZXJhdGlvbi5odG1sI19tYXBzLTFcbiAgICogQHNlZSBodHRwczovL2dpdGh1Yi5jb20vc2luZHJlc29yaHVzL3F1aWNrLWxydS9ibG9iL21hc3Rlci9pbmRleC5qc1xuICAgKiBAc2VlIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzM2OTc2ODMyL3doYXQtaXMtdGhlLW1lYW5pbmctb2Ytc3ltYm9sLWl0ZXJhdG9yLWluLXRoaXMtY29udGV4dFxuICAgKiBAc2VlIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL1N5bWJvbC9pdGVyYXRvclxuICAgKiBAc2VlIHRoaXMuc3RvcmVcbiAgICpcbiAgICogQHRlc3RzIGl0ZXJhdGlvblxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICBjb25zdCBjaGFpbiA9IG5ldyBDaGFpbigpLnNldCgnZWgnLCAxKVxuICAgKiAgICBmb3IgKHZhciBba2V5LCB2YWxdIG9mIGNoYWluKSBjb25zb2xlLmxvZyh7W2tleV06IHZhbH0pXG4gICAqICAgIC8vPT4ge2VoOiAxfVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAqW1N5bWJvbC5pdGVyYXRvcl0oKTogdm9pZCB7IGZvciAoY29uc3QgaXRlbSBvZiB0aGlzLnN0b3JlKSB5aWVsZCBpdGVtIH1cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgY29uc3Qge0NoYWluZWRTZXR9ID0gcmVxdWlyZSgnY2hhaW4tYWJsZScpXG4gICAqICAgIGNvbnN0IHNldCA9IG5ldyBDaGFpbmVkU2V0KClcbiAgICogICAgc2V0LmFkZCgnZWgnKVxuICAgKlxuICAgKiAgICBmb3IgKGNvbnN0IGFyciBvZiBzZXQpIHtcbiAgICogICAgICBjb25zdCBba2V5LCB2YWxdID0gYXJyXG4gICAqXG4gICAqICAgICAga2V5ICAgICAgICAvLz0+IDBcbiAgICogICAgICB2YWwgICAgICAgIC8vPT4gJ2VoJ1xuICAgKiAgICAgIGFyci5sZW5ndGggLy89PiAyXG4gICAqICAgIH1cbiAgICpcbiAgICovXG4gIENoYWluYWJsZS5wcm90b3R5cGVbU3ltYm9sSXRlcmF0b3JdID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIGtleVZhbHVlVG9JdGVyYXRvcih0aGlzLmtleXMoKSwgdGhpcy52YWx1ZXMoKSwgdGhpcy5zdG9yZS5zaXplKVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjIHN5bWJvbCBtZXRob2QgZm9yIHRvU3RyaW5nLCB0b0pTT04sIHRvTnVtYmVyXG4gICAqIEBtZW1iZXJPZiBDaGFpbmFibGVcbiAgICogQHNpbmNlIDEuMC4yXG4gICAqIEB2ZXJzaW9uIDJcbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGhpbnQgZW51bVtkZWZhdWx0LCBzdHJpbmcsIG51bWJlcl1cbiAgICogQHJldHVybiB7UHJpbWl0aXZlfVxuICAgKlxuICAgKiB7QGxpbmsgaHR0cDovLzJhbGl0eS5jb20vMjAxNS8wOS93ZWxsLWtub3duLXN5bWJvbHMtZXM2Lmh0bWwjZGVmYXVsdC10b3N0cmluZy10YWdzIHdlbGwta25vd24tc3ltYm9scy1lczZ9XG4gICAqIEBzZWUge0BsaW5rIHdlbGwta25vd24tc3ltYm9scy1lczZ9XG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICBjb25zdCBjaGFpbiA9IG5ldyBDaGFpbigpXG4gICAqICBjaGFpbi50b051bWJlciA9ICgpID0+IDFcbiAgICogICtjaGFpbjtcbiAgICogIC8vPT4gMVxuICAgKiAgY2hhaW4gKyAxXG4gICAqICAvLz0+XG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICBjb25zdCBjaGFpbiA9IG5ldyBDaGFpbigpXG4gICAqICBjaGFpbi50b1N0cmluZyA9ICgpID0+ICdlaCdcbiAgICogIGNoYWluICsgJydcbiAgICogIC8vPT4gJ2VoJ1xuICAgKlxuICAgKi9cbiAgQ2hhaW5hYmxlLnByb3RvdHlwZVtTeW1ib2xQcmltaXRpdmVdID0gZnVuY3Rpb24oaGludCkge1xuICAgIC8qIHByZXR0aWVyLWlnbm9yZSAqL1xuICAgIC8qKlxuICAgICAqIGhpbnQgPT09ICdudW1iZXInXG4gICAgICogYHNgdHJpbmcgaXMgMTE1XG4gICAgICogYG5gdW1iZXIgaXMgMTEwXG4gICAgICogMTEwICYgNCA9IDFcbiAgICAgKiAxMTUgJiA0ID0gMFxuICAgICAqXG4gICAgICogaWYgKGhpbnQgPT09ICdzdHJpbmcnICYmIHRoaXMudG9KU09OKSByZXR1cm4gdGhpcy50b0pTT04oKVxuICAgICAqIGVsc2UgaWYgKGhpbnQgPT09ICdudW1iZXInICYmIHRoaXMudG9OdW1iZXIpIHJldHVybiB0aGlzLnRvTnVtYmVyKClcbiAgICAgKi9cbiAgICBpZiAoaGludCA9PT0gJ251bWJlcicgJiYgdGhpcy50b051bWJlcikgcmV0dXJuIHRoaXMudG9OdW1iZXIoKVxuXG4gICAgLy8gaGludCA9PT0gJ3N0cmluZydcbiAgICBpZiAodGhpcy50b0pTT04pIHJldHVybiB0aGlzLnRvSlNPTigpXG5cbiAgICAvLyBoaW50ID09PSAnZGVmYXVsdCdcbiAgICByZXR1cm4gdGhpcy50b1N0cmluZygpXG4gIH1cblxuICAvKipcbiAgICogQG1lbWJlck9mIENoYWluYWJsZVxuICAgKiBAbmFtZSBsZW5ndGhcbiAgICogQG1ldGhvZCBsZW5ndGhcbiAgICogQHJlYWRvbmx5XG4gICAqIEBzaW5jZSAwLjUuMFxuICAgKiBAc2VlIENoYWluZWRNYXAuc3RvcmVcbiAgICogQHJldHVybiB7bnVtYmVyfVxuICAgKiBAZXhhbXBsZSBmb3IgKHZhciBpID0gMDsgaSA8IGNoYWluLmxlbmd0aDsgaSsrKVxuICAgKi9cbiAgT2JqZWN0RGVmaW5lKENoYWluYWJsZS5wcm90b3R5cGUsICdsZW5ndGgnLCB7XG4gICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgZ2V0KCkge1xuICAgICAgcmV0dXJuIHRoaXMuc3RvcmUuc2l6ZVxuICAgIH0sXG4gIH0pXG4gIE9iamVjdERlZmluZShDaGFpbmFibGUucHJvdG90eXBlLCBTeW1ib2xJbnN0YW5jZSwge1xuICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgIHZhbHVlOiBpbnN0YW5jZSA9PlxuICAgICAgaW5zdGFuY2UgJiZcbiAgICAgIChpc1Byb3RvdHlwZU9mKENoYWluYWJsZS5wcm90b3R5cGUsIGluc3RhbmNlKSB8fCBoYXNTdG9yZShpbnN0YW5jZSkpLFxuICB9KVxuXG4gIC8vIEBUT0RPIHRvIHdyYXAgaW4gdG9GdW5jdGlvbiBidXQga2VlcCBwcm90b3R5cGVcbiAgLy8gcmV0dXJuIGZ1bmN0aW9uKHBhcmVudCkge1xuICAvLyAgIGNvbnN0IGluc3RhbmNlID0gbmV3IENoYWluYWJsZShwYXJlbnQpXG4gIC8vICAgLy8gY29uc29sZS5sb2coe2luc3RhbmNlfSwgaW5zdGFuY2UuZW5kKVxuICAvLyAgIHJldHVybiBpbnN0YW5jZVxuICAvLyB9XG5cbiAgcmV0dXJuIENoYWluYWJsZVxufVxuXG4vKipcbiAqIEBzaW5jZSAzLjAuMFxuICogQGZ1bmNcbiAqIEBleGFtcGxlXG4gKlxuICogIGNsYXNzIFRhcmdldCB7fVxuICogIGNvbnN0IFRhcmdldENoYWluID0gQ2hhaW5hYmxlLmNvbXBvc2UoVGFyZ2V0KVxuICogIGNvbnN0IGNoYWluID0gbmV3IFRhcmdldENoYWluKClcbiAqICBjaGFpbiBpbnN0YW5jZW9mIFRhcmdldFxuICogIC8vPT4gdHJ1ZVxuICpcbiAqL1xuY29uc3QgYyA9IGNvbXBvc2VyKENvbXBvc2VDaGFpbmFibGUsIG5vb3ApXG5cbm1vZHVsZS5leHBvcnRzID0gY1xuIl0sIm5hbWVzIjpbImNvbnN0Iiwic3VwZXIiLCJsZXQiLCJ0aGlzIl0sIm1hcHBpbmdzIjoiQUFBQTs7QUFFQUEsR0FBSyxDQUFDLGVBQWUsR0FBRyxPQUFPLENBQUMsZ0JBQWdCLENBQUM7QUFDakRBLEdBQUssQ0FBQyxjQUFjLEdBQUcsT0FBTyxDQUFDLHlCQUF5QixDQUFDO0FBQ3pEQSxHQUFLLENBQUMsY0FBYyxHQUFHLE9BQU8sQ0FBQyx5QkFBeUIsQ0FBQztBQUN6REEsR0FBSyxDQUFDLGVBQWUsR0FBRyxPQUFPLENBQUMsMEJBQTBCLENBQUM7QUFDM0RBLEdBQUssQ0FBQyxhQUFhLEdBQUcsT0FBTyxDQUFDLHVCQUF1QixDQUFDO0FBQ3REQSxHQUFLLENBQUMsS0FBSyxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUM7QUFDdENBLEdBQUssQ0FBQyxLQUFLLEdBQUcsT0FBTyxDQUFDLGVBQWUsQ0FBQztBQUN0Q0EsR0FBSyxDQUFDLE1BQU0sR0FBRyxPQUFPLENBQUMsZ0JBQWdCLENBQUM7QUFDeENBLEdBQUssQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFDLHFCQUFxQixDQUFDO0FBQ2xEQSxHQUFLLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztBQUM1Q0EsR0FBSyxDQUFD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