UNPKG

foop

Version:

interfaces that describe their intentions.

508 lines (466 loc) 40.3 kB
/* 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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