UNPKG

chain-able

Version:

interfaces that describe their intentions.

325 lines (300 loc) 29.3 kB
/* eslint complexity: "OFF" */ var MethodChain = require('./MethodChain') var ChainedMapBase = require('./ChainedMapBase') var dopemerge = require('./deps/dopemerge') var isFunction = require('./deps/is/function') var isUndefined = require('./deps/is/undefined') var isTrue = require('./deps/is/true') var isMapish = require('./deps/is/mapish') var ObjectKeys = require('./deps/util/keys') var SHORTHANDS_KEY = require('./deps/meta/shorthands') var ENV_DEVELOPMENT = require('./deps/env/dev') var ENV_DEBUG = require('./deps/env/debug') var ON_EXISTING_KEY = 'onExisting' var ON_VALUE_KEY = 'onValue' var MERGER_KEY = 'merger' var MERGER_OPTIONS_KEY = 'opts' var OBJ_KEY = 'obj' /** * @since 1.0.0 * @type {Map} * @extends {ChainedMapBase} * @member MergeChain * @memberOf Chainable * * @types MergeChain * @tests MergeChain * @see deps/dopemerge * * {@link https://sourcemaking.com/design_patterns/visitor visitor-pattern} * * @TODO consider just making this a function, * because 80/20 onValue merger & onExisting * are rarely used & are easily overridable with .merge */ var MergeChain = (function (ChainedMapBase) { function MergeChain(parent) { ChainedMapBase.call(this, parent) /* prettier-ignore */ this .extend([ON_EXISTING_KEY, ON_VALUE_KEY, OBJ_KEY]) .set(ON_VALUE_KEY, function () { return true; }) .set(MERGER_KEY, dopemerge) } if ( ChainedMapBase ) MergeChain.__proto__ = ChainedMapBase; MergeChain.prototype = Object.create( ChainedMapBase && ChainedMapBase.prototype ); MergeChain.prototype.constructor = MergeChain; /** * @desc options for merging with dopemerge * @modifies this.merger | this.opts * * @memberOf MergeChain * @since 1.0.2 * @param {Object | Function} opts when object: options for the merger. when function: is the merger * @return {MergeChain} @chainable * @see dopemerge * * @example * { * stringToArray: true, * boolToArray: false, * boolAsRight: true, * ignoreTypes: ['null', 'undefined', 'NaN'], * debug: false, * } * * @example * .merger(require('lodash.mergewith')()) */ MergeChain.init = function init (parent) { return new MergeChain(parent) }; MergeChain.prototype.merger = function merger (opts) { if (isFunction(opts)) { return this.set(MERGER_KEY, opts) } return this.set(MERGER_OPTIONS_KEY, opts) }; // [v] messes comments on conditional brace style /* prettier-ignore */ /** * @desc merges object in, goes through all keys, checks cbs, dopemerges * * @since 1.0.0 * * @param {Object} [obj2=undefined] object to merge in, defaults to this.get('obj') * @return {MergeChain} @chainable * * @see ChainedMap * @TODO issue here if we extend without shorthands & * we want to merge existing values... :s * * * @example * * const chain = new Chain() * chain.merge({canada: {eh: true}}) * chain.merge({canada: {arr: [0, {'1': 2}], eh: {again: true}}}) * chain.entries() * //=> {canada:{ eh: {again: true}, arr: [0, {'1': 2}] }} */ MergeChain.prototype.merge = function merge (obj2) { var this$1 = this; // better uglifying var parent = this.parent var get = function (key) { return this$1.get(key); } var onExisting = get(ON_EXISTING_KEY) var onValue = get(ON_VALUE_KEY) var opts = get(MERGER_OPTIONS_KEY) var obj = obj2 || get(OBJ_KEY) var merger = get(MERGER_KEY) var shorthands = parent.meta ? parent.meta(SHORTHANDS_KEY) : {} var keys = ObjectKeys(obj) // @@debugger /* istanbul ignore next: devs */ if (ENV_DEVELOPMENT) { if (!obj) { console.log({onExisting: onExisting, opts: opts, obj: obj, merger: merger, shorthands: shorthands, keys: keys, parent: parent}) throw new Error('must provide an object to merge') } } /** * @private * * since this would be slower * if I want to not have a speedy default when using .onExisting * should @note to use .extend * when using chains without a class & doing .merge (edge-case) * * @param {Primitive} key key (shorthands[key] or just key) * @param {*} value obj[key] * @return {void} * * @TODO could use .eq here * @TODO if (isMapish(obj)) obj = obj.entries() * * @example * var obj = {key: 1} * * MergeChain.init(obj).merge({key: ['value']}) * * // goes to this internal scoped function * handleExisting('key', ['value']) * // if there is .onValue or .onExisting, use them, default deepmerge * * obj * //=> {key: [1, 'value']} * */ var handleExisting = function (key, value) { /** * @desc when fn is a full method, not an extended shorthand * @since 0.5.0 * * @param {Primitive} keyToSet key we chose to set * @param {*} valueToSet value we chose to set (merged, existing, new) * @return {Parent | Chain | *} .set or [keyToSet] return * * @example * * MergeChain.init(new Chain().extend(['eh'])) * * //isFunction: true => call parent[keyToSet](valueToSet) * setChosen('eh', 1) * //=> parent * parent.get('eh') * //=> 1 * * //=>isFunction: false => parent.set(keyToSet, valueToSet) * setChosen('oh', 1) * //=> parent //<- unless .set is overriden * parent.get('oh') * //=> 1 */ var setChosen = function (keyToSet, valueToSet) { return (isFunction(parent[key]) ? parent[keyToSet](valueToSet) : parent.set(keyToSet, valueToSet)); } /** * check if it's shorthanded * -> check if it has a value already */ if (isTrue(parent.has(key))) { // get that value var existing = parent.get(key) /** * if we have onExisting, call it * else default to dopemerge */ if (isUndefined(onExisting)) { /* istanbul ignore next: devs */ if (ENV_DEBUG) { console.log( 'parent has: no onExisting', {existing: existing, [key]: value} ) } setChosen(key, merger(existing, value, opts)) } else { /* istanbul ignore next: devs */ if (ENV_DEBUG) { console.log( 'parent has: has onExisting', {existing: existing, onExisting: onExisting, [key]: value} ) } /** * maybe we should not even have `.onExisting` * since we can just override merge method... * and then client can just use a custom merger... * * could add and remove subscriber but that's overhead and * tricky here, because if we set a value that was just set... */ setChosen(key, onExisting(existing, value, opts)) } } else { /* istanbul ignore next: devs */ if (ENV_DEBUG) { console.log('parent does not have', {[key]: value}) } setChosen(key, value) } } for (var k = 0, len = keys.length; k < len; k++) { // key to the current property in the data being merged var key = keys[k] // we have our value, no we can change the key if needed for shorthands var value = obj[key] // @NOTE: when shorthands is an object, key is the method it should call if (!isUndefined(shorthands[key]) && shorthands[key] !== key) { /* istanbul ignore next: devs */ if (ENV_DEBUG) { console.log( 'had a shorthand with a diff key than the object (likely @alias)', {shorthandMethod: shorthands[key], key: key, value: value} ) } key = shorthands[key] } // method for the key var method = parent[key] /* istanbul ignore next: sourcemaps trigger istanbul here incorrectly */ // use onValue when set if (!onValue(value, key, this$1)) { /* istanbul ignore next: devs */ if (ENV_DEBUG) { console.log('had onValue, was false, ignored', {onValue: onValue, key: key, value: value}) } continue } // when property itself is a Chainable else if (isMapish(method)) { /* istanbul ignore next: devs */ if (ENV_DEBUG) { console.log('has method or shorthand') } parent[key].merge(value) } // we have a method or shorthand else if (method) { /* istanbul ignore next: devs */ if (ENV_DEBUG) { console.log('has method or shorthand', {method: method, key: key, value: value}) } handleExisting(key, value) } // default to .set on the store else { /* istanbul ignore next: devs */ if (ENV_DEBUG) { console.log('went to default', {method: method, key: key, value: value}) } parent.set(key, value) } } return parent }; return MergeChain; }(ChainedMapBase)); /** * @memberOf MergeChain * @method onExisting * @since 0.9.0 * @example * const {Chain, MergeChain} = require('chain-able') * * const chain = new Chain().set('str', 'stringy') * * MergeChain.init(chain) * .onExisting((a, b) => a + b) * .merge({str: '+'}) * * chain.get('str') * //=> 'stringy+' */ module.exports = MergeChain // @TODO re-enable this later // module.exports = new MethodChain(MergeChain.prototype) // .methods(['onExisting', 'onValue', 'obj']) // .build(MergeChain) //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWVyZ2VDaGFpbi5qcyIsInNvdXJjZXMiOlsiTWVyZ2VDaGFpbi5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQgY29tcGxleGl0eTogXCJPRkZcIiAqL1xuY29uc3QgTWV0aG9kQ2hhaW4gPSByZXF1aXJlKCcuL01ldGhvZENoYWluJylcbmNvbnN0IENoYWluZWRNYXBCYXNlID0gcmVxdWlyZSgnLi9DaGFpbmVkTWFwQmFzZScpXG5jb25zdCBkb3BlbWVyZ2UgPSByZXF1aXJlKCcuL2RlcHMvZG9wZW1lcmdlJylcbmNvbnN0IGlzRnVuY3Rpb24gPSByZXF1aXJlKCcuL2RlcHMvaXMvZnVuY3Rpb24nKVxuY29uc3QgaXNVbmRlZmluZWQgPSByZXF1aXJlKCcuL2RlcHMvaXMvdW5kZWZpbmVkJylcbmNvbnN0IGlzVHJ1ZSA9IHJlcXVpcmUoJy4vZGVwcy9pcy90cnVlJylcbmNvbnN0IGlzTWFwaXNoID0gcmVxdWlyZSgnLi9kZXBzL2lzL21hcGlzaCcpXG5jb25zdCBPYmplY3RLZXlzID0gcmVxdWlyZSgnLi9kZXBzL3V0aWwva2V5cycpXG5jb25zdCBTSE9SVEhBTkRTX0tFWSA9IHJlcXVpcmUoJy4vZGVwcy9tZXRhL3Nob3J0aGFuZHMnKVxuY29uc3QgRU5WX0RFVkVMT1BNRU5UID0gcmVxdWlyZSgnLi9kZXBzL2Vudi9kZXYnKVxuY29uc3QgRU5WX0RFQlVHID0gcmVxdWlyZSgnLi9kZXBzL2Vudi9kZWJ1ZycpXG5cbmNvbnN0IE9OX0VYSVNUSU5HX0tFWSA9ICdvbkV4aXN0aW5nJ1xuY29uc3QgT05fVkFMVUVfS0VZID0gJ29uVmFsdWUnXG5jb25zdCBNRVJHRVJfS0VZID0gJ21lcmdlcidcbmNvbnN0IE1FUkdFUl9PUFRJT05TX0tFWSA9ICdvcHRzJ1xuY29uc3QgT0JKX0tFWSA9ICdvYmonXG5cbi8qKlxuICogQHNpbmNlIDEuMC4wXG4gKiBAdHlwZSB7TWFwfVxuICogQGV4dGVuZHMge0NoYWluZWRNYXBCYXNlfVxuICogQG1lbWJlciBNZXJnZUNoYWluXG4gKiBAbWVtYmVyT2YgQ2hhaW5hYmxlXG4gKlxuICogQHR5cGVzIE1lcmdlQ2hhaW5cbiAqIEB0ZXN0cyBNZXJnZUNoYWluXG4gKiBAc2VlIGRlcHMvZG9wZW1lcmdlXG4gKlxuICoge0BsaW5rIGh0dHBzOi8vc291cmNlbWFraW5nLmNvbS9kZXNpZ25fcGF0dGVybnMvdmlzaXRvciB2aXNpdG9yLXBhdHRlcm59XG4gKlxuICogQFRPRE8gY29uc2lkZXIganVzdCBtYWtpbmcgdGhpcyBhIGZ1bmN0aW9uLFxuICogICAgICAgYmVjYXVzZSA4MC8yMCBvblZhbHVlIG1lcmdlciAmIG9uRXhpc3RpbmdcbiAqICAgICAgIGFyZSByYXJlbHkgdXNlZCAmIGFyZSBlYXNpbHkgb3ZlcnJpZGFibGUgd2l0aCAubWVyZ2VcbiAqL1xuY2xhc3MgTWVyZ2VDaGFpbiBleHRlbmRzIENoYWluZWRNYXBCYXNlIHtcbiAgLyoqXG4gICAqIEBzdGF0aWNcbiAgICogQHBhcmFtICB7Q2hhaW5hYmxlIHwgUGFyZW50VHlwZX0gcGFyZW50IFBhcmVudFR5cGUgcmVxdWlyZWQsIGZvciBtZXJnaW5nXG4gICAqIEByZXR1cm4ge01lcmdlQ2hhaW59IEBjaGFpbmFibGVcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgbGV0IG1hcCA9IG5ldyBNYXAoKVxuICAgKiAgICBtYXAuc2V0KCdlaCcsIDEpXG4gICAqICAgIG1hcC5zZXQoJ2NvbycsICdvbycpXG4gICAqXG4gICAqICAgIE1lcmdlQ2hhaW4uaW5pdChtYXApLm1lcmdlKHtlaDogMn0pXG4gICAqICAgIGNvbnNvbGUuZGlyKG1hcClcbiAgICogICAgLy89PiBNYXAgeyAnZWgnID0+IDIsICdjb28nID0+ICdvbycgfVxuICAgKlxuICAgKi9cbiAgc3RhdGljIGluaXQocGFyZW50KSB7XG4gICAgcmV0dXJuIG5ldyBNZXJnZUNoYWluKHBhcmVudClcbiAgfVxuXG4gIC8qKlxuICAgKiBAaW5oZXJpdGRvY1xuICAgKi9cbiAgY29uc3RydWN0b3IocGFyZW50KSB7XG4gICAgc3VwZXIocGFyZW50KVxuXG4gICAgLyogcHJldHRpZXItaWdub3JlICovXG4gICAgdGhpc1xuICAgICAgLmV4dGVuZChbT05fRVhJU1RJTkdfS0VZLCBPTl9WQUxVRV9LRVksIE9CSl9LRVldKVxuICAgICAgLnNldChPTl9WQUxVRV9LRVksICgpID0+IHRydWUpXG4gICAgICAuc2V0KE1FUkdFUl9LRVksIGRvcGVtZXJnZSlcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzYyBvcHRpb25zIGZvciBtZXJnaW5nIHdpdGggZG9wZW1lcmdlXG4gICAqICAgICAgIEBtb2RpZmllcyB0aGlzLm1lcmdlciB8IHRoaXMub3B0c1xuICAgKlxuICAgKiBAbWVtYmVyT2YgTWVyZ2VDaGFpblxuICAgKiBAc2luY2UgMS4wLjJcbiAgICogQHBhcmFtICB7T2JqZWN0IHwgRnVuY3Rpb259IG9wdHMgd2hlbiBvYmplY3Q6IG9wdGlvbnMgZm9yIHRoZSBtZXJnZXIuIHdoZW4gZnVuY3Rpb246IGlzIHRoZSBtZXJnZXJcbiAgICogQHJldHVybiB7TWVyZ2VDaGFpbn0gQGNoYWluYWJsZVxuICAgKiBAc2VlIGRvcGVtZXJnZVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiAgIHtcbiAgICogICAgIHN0cmluZ1RvQXJyYXk6IHRydWUsXG4gICAqICAgICBib29sVG9BcnJheTogZmFsc2UsXG4gICAqICAgICBib29sQXNSaWdodDogdHJ1ZSxcbiAgICogICAgIGlnbm9yZVR5cGVzOiBbJ251bGwnLCAndW5kZWZpbmVkJywgJ05hTiddLFxuICAgKiAgICAgZGVidWc6IGZhbHNlLFxuICAgKiAgIH1cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogICAgLm1lcmdlcihyZXF1aXJlKCdsb2Rhc2gubWVyZ2V3aXRoJykoKSlcbiAgICovXG4gIG1lcmdlcihvcHRzKSB7XG4gICAgaWYgKGlzRnVuY3Rpb24ob3B0cykpIHJldHVybiB0aGlzLnNldChNRVJHRVJfS0VZLCBvcHRzKVxuICAgIHJldHVybiB0aGlzLnNldChNRVJHRVJfT1BUSU9OU19LRVksIG9wdHMpXG4gIH1cblxuICAvLyBbdl0gbWVzc2VzIGNvbW1lbnRzIG9uIGNvbmRpdGlvbmFsIGJyYWNlIHN0eWxlXG4gIC8qIHByZXR0aWVyLWlnbm9yZSAqL1xuICAvKipcbiAgICogQGRlc2MgbWVyZ2VzIG9iamVjdCBpbiwgZ29lcyB0aHJvdWdoIGFsbCBrZXlzLCBjaGVja3MgY2JzLCBkb3BlbWVyZ2VzXG4gICAqXG4gICAqIEBzaW5jZSAxLjAuMFxuICAgKlxuICAgKiBAcGFyYW0gIHtPYmplY3R9IFtvYmoyPXVuZGVmaW5lZF0gb2JqZWN0IHRvIG1lcmdlIGluLCBkZWZhdWx0cyB0byB0aGlzLmdldCgnb2JqJylcbiAgICogQHJldHVybiB7TWVyZ2VDaGFpbn0gQGNoYWluYWJsZVxuICAgKlxuICAgKiBAc2VlIENoYWluZWRNYXBcbiAgICogQFRPRE8gaXNzdWUgaGVyZSBpZiB3ZSBleHRlbmQgd2l0aG91dCBzaG9ydGhhbmRzICZcbiAgICogICAgICAgd2Ugd2FudCB0byBtZXJnZSBleGlzdGluZyB2YWx1ZXMuLi4gOnNcbiAgICpcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogIGNvbnN0IGNoYWluID0gbmV3IENoYWluKClcbiAgICogIGNoYWluLm1lcmdlKHtjYW5hZGE6IHtlaDogdHJ1ZX19KVxuICAgKiAgY2hhaW4ubWVyZ2Uoe2NhbmFkYToge2FycjogWzAsIHsnMSc6IDJ9XSwgZWg6IHthZ2FpbjogdHJ1ZX19fSlcbiAgICogIGNoYWluLmVudHJpZXMoKVxuICAgKiAgLy89PiB7Y2FuYWRhOnsgZWg6IHthZ2FpbjogdHJ1ZX0sIGFycjogWzAsIHsnMSc6IDJ9XSB9fVxuICAgKi9cbiAgbWVyZ2Uob2JqMikge1xuICAgIC8vIGJldHRlciB1Z2xpZnlpbmdcbiAgICBjb25zdCBwYXJlbnQgPSB0aGlzLnBhcmVudFxuICAgIGNvbnN0IGdldCA9IGtleSA9PiB0aGlzLmdldChrZXkpXG5cbiAgICBjb25zdCBvbkV4aXN0aW5nID0gZ2V0KE9OX0VYSVNUSU5HX0tFWSlcbiAgICBjb25zdCBvblZhbHVlID0gZ2V0KE9OX1ZBTFVFX0tFWSlcbiAgICBjb25zdCBvcHRzID0gZ2V0KE1FUkdFUl9PUFRJT05TX0tFWSlcbiAgICBjb25zdCBvYmogPSBvYmoyIHx8IGdldChPQkpfS0VZKVxuICAgIGNvbnN0IG1lcmdlciA9IGdldChNRVJHRVJfS0VZKVxuICAgIGNvbnN0IHNob3J0aGFuZHMgPSBwYXJlbnQubWV0YSA/IHBhcmVudC5tZXRhKFNIT1JUSEFORFNfS0VZKSA6IHt9XG4gICAgY29uc3Qga2V5cyA9IE9iamVjdEtleXMob2JqKVxuXG4gICAgLy8gQEBkZWJ1Z2dlclxuXG4gICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQ6IGRldnMgKi9cbiAgICBpZiAoRU5WX0RFVkVMT1BNRU5UKSB7XG4gICAgICBpZiAoIW9iaikge1xuICAgICAgICBjb25zb2xlLmxvZyh7b25FeGlzdGluZywgb3B0cywgb2JqLCBtZXJnZXIsIHNob3J0aGFuZHMsIGtleXMsIHBhcmVudH0pXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignbXVzdCBwcm92aWRlIGFuIG9iamVjdCB0byBtZXJnZScpXG4gICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHByaXZhdGVcbiAgICAgKlxuICAgICAqIHNpbmNlIHRoaXMgd291bGQgYmUgc2xvd2VyXG4gICAgICogaWYgSSB3YW50IHRvIG5vdCBoYXZlIGEgc3BlZWR5IGRlZmF1bHQgd2hlbiB1c2luZyAub25FeGlzdGluZ1xuICAgICAqIHNob3VsZCBAbm90ZSB0byB1c2UgLmV4dGVuZFxuICAgICAqIHdoZW4gdXNpbmcgY2hhaW5zIHdpdGhvdXQgYSBjbGFzcyAmIGRvaW5nIC5tZXJnZSAoZWRnZS1jYXNlKVxuICAgICAqXG4gICAgICogQHBhcmFtICB7UHJpbWl0aXZlfSBrZXkga2V5IChzaG9ydGhhbmRzW2tleV0gb3IganVzdCBrZXkpXG4gICAgICogQHBhcmFtICB7Kn0gdmFsdWUgb2JqW2tleV1cbiAgICAgKiBAcmV0dXJuIHt2b2lkfVxuICAgICAqXG4gICAgICogQFRPRE8gY291bGQgdXNlIC5lcSBoZXJlXG4gICAgICogQFRPRE8gaWYgKGlzTWFwaXNoKG9iaikpIG9iaiA9IG9iai5lbnRyaWVzKClcbiAgICAgKlxuICAgICAqIEBleGFtcGxlXG4gICAgICogIHZhciBvYmogPSB7a2V5OiAxfVxuICAgICAqXG4gICAgICogIE1lcmdlQ2hhaW4uaW5pdChvYmopLm1lcmdlKHtrZXk6IFsndmFsdWUnXX0pXG4gICAgICpcbiAgICAgKiAgLy8gZ29lcyB0byB0aGlzIGludGVybmFsIHNjb3BlZCBmdW5jdGlvblxuICAgICAqICBoYW5kbGVFeGlzdGluZygna2V5JywgWyd2YWx1ZSddKVxuICAgICAqICAvLyBpZiB0aGVyZSBpcyAub25WYWx1ZSBvciAub25FeGlzdGluZywgdXNlIHRoZW0sIGRlZmF1bHQgZGVlcG1lcmdlXG4gICAgICpcbiAgICAgKiAgb2JqXG4gICAgICogIC8vPT4ge2tleTogWzEsICd2YWx1ZSddfVxuICAgICAqXG4gICAgICovXG4gICAgY29uc3QgaGFuZGxlRXhpc3RpbmcgPSAoa2V5LCB2YWx1ZSkgPT4ge1xuICAgICAgLyoqXG4gICAgICAgKiBAZGVzYyB3aGVuIGZuIGlzIGEgZnVsbCBtZXRob2QsIG5vdCBhbiBleHRlbmRlZCBzaG9ydGhhbmRcbiAgICAgICAqIEBzaW5jZSAwLjUuMFxuICAgICAgICpcbiAgICAgICAqIEBwYXJhbSB7UHJpbWl0aXZlfSBrZXlUb1NldCBrZXkgd2UgY2hvc2UgdG8gc2V0XG4gICAgICAgKiBAcGFyYW0geyp9IHZhbHVlVG9TZXQgdmFsdWUgd2UgY2hvc2UgdG8gc2V0IChtZXJnZWQsIGV4aXN0aW5nLCBuZXcpXG4gICAgICAgKiBAcmV0dXJuIHtQYXJlbnQgfCBDaGFpbiB8ICp9IC5zZXQgb3IgW2tleVRvU2V0XSByZXR1cm5cbiAgICAgICAqXG4gICAgICAgKiBAZXhhbXBsZVxuICAgICAgICpcbiAgICAgICAqICAgIE1lcmdlQ2hhaW4uaW5pdChuZXcgQ2hhaW4oKS5leHRlbmQoWydlaCddKSlcbiAgICAgICAqXG4gICAgICAgKiAgICAvL2lzRnVuY3Rpb246IHRydWUgPT4gY2FsbCBwYXJlbnRba2V5VG9TZXRdKHZhbHVlVG9TZXQpXG4gICAgICAgKiAgICBzZXRDaG9zZW4oJ2VoJywgMSlcbiAgICAgICAqICAgIC8vPT4gcGFyZW50XG4gICAgICAgKiAgICBwYXJlbnQuZ2V0KCdlaCcpXG4gICAgICAgKiAgICAvLz0+IDFcbiAgICAgICAqXG4gICAgICAgKiAgICAvLz0+aXNGdW5jdGlvbjogZmFsc2UgPT4gcGFyZW50LnNldChrZXlUb1NldCwgdmFsdWVUb1NldClcbiAgICAgICAqICAgIHNldENob3Nlbignb2gnLCAxKVxuICAgICAgICogICAgLy89PiBwYXJlbnQgLy88LSB1bmxlc3MgLnNldCBpcyBvdmVycmlkZW5cbiAgICAgICAqICAgIHBhcmVudC5nZXQoJ29oJylcbiAgICAgICAqICAgIC8vPT4gMVxuICAgICAgICovXG4gICAgICBjb25zdCBzZXRDaG9zZW4gPSAoa2V5VG9TZXQsIHZhbHVlVG9TZXQpID0+XG4gICAgICAgIChpc0Z1bmN0aW9uKHBhcmVudFtrZXldKVxuICAgICAgICAgID8gcGFyZW50W2tleVRvU2V0XSh2YWx1ZVRvU2V0KVxuICAgICAgICAgIDogcGFyZW50LnNldChrZXlUb1NldCwgdmFsdWVUb1NldCkpXG5cbiAgICAgIC8qKlxuICAgICAgICogY2hlY2sgaWYgaXQncyBzaG9ydGhhbmRlZFxuICAgICAgICogLT4gY2hlY2sgaWYgaXQgaGFzIGEgdmFsdWUgYWxyZWFkeVxuICAgICAgICovXG4gICAgICBpZiAoaXNUcnVlKHBhcmVudC5oYXMoa2V5KSkpIHtcbiAgICAgICAgLy8gZ2V0IHRoYXQgdmFsdWVcbiAgICAgICAgY29uc3QgZXhpc3RpbmcgPSBwYXJlbnQuZ2V0KGtleSlcblxuICAgICAgICAvKipcbiAgICAgICAgICogaWYgd2UgaGF2ZSBvbkV4aXN0aW5nLCBjYWxsIGl0XG4gICAgICAgICAqIGVsc2UgZGVmYXVsdCB0byBkb3BlbWVyZ2VcbiAgICAgICAgICovXG4gICAgICAgIGlmIChpc1VuZGVmaW5lZChvbkV4aXN0aW5nKSkge1xuICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBkZXZzICovXG4gICAgICAgICAgaWYgKEVOVl9ERUJVRykge1xuICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgICdwYXJlbnQgaGFzOiBubyBvbkV4aXN0aW5nJyxcbiAgICAgICAgICAgICAge2V4aXN0aW5nLCBba2V5XTogdmFsdWV9XG4gICAgICAgICAgICApXG4gICAgICAgICAgfVxuICAgICAgICAgIHNldENob3NlbihrZXksIG1lcmdlcihleGlzdGluZywgdmFsdWUsIG9wdHMpKVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBkZXZzICovXG4gICAgICAgICAgaWYgKEVOVl9ERUJVRykge1xuICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgICdwYXJlbnQgaGFzOiBoYXMgb25FeGlzdGluZycsXG4gICAgICAgICAgICAgIHtleGlzdGluZywgb25FeGlzdGluZywgW2tleV06IHZhbHVlfVxuICAgICAgICAgICAgKVxuICAgICAgICAgIH1cbiAgICAgICAgICAvKipcbiAgICAgICAgICAgKiBtYXliZSB3ZSBzaG91bGQgbm90IGV2ZW4gaGF2ZSBgLm9uRXhpc3RpbmdgXG4gICAgICAgICAgICogc2luY2Ugd2UgY2FuIGp1c3Qgb3ZlcnJpZGUgbWVyZ2UgbWV0aG9kLi4uXG4gICAgICAgICAgICogYW5kIHRoZW4gY2xpZW50IGNhbiBqdXN0IHVzZSBhIGN1c3RvbSBtZXJnZXIuLi5cbiAgICAgICAgICAgKlxuICAgICAgICAgICAqIGNvdWxkIGFkZCBhbmQgcmVtb3ZlIHN1YnNjcmliZXIgYnV0IHRoYXQncyBvdmVyaGVhZCBhbmRcbiAgICAgICAgICAgKiB0cmlja3kgaGVyZSwgYmVjYXVzZSBpZiB3ZSBzZXQgYSB2YWx1ZSB0aGF0IHdhcyBqdXN0IHNldC4uLlxuICAgICAgICAgICAqL1xuICAgICAgICAgIHNldENob3NlbihrZXksIG9uRXhpc3RpbmcoZXhpc3RpbmcsIHZhbHVlLCBvcHRzKSlcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZWxzZSB7XG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBkZXZzICovXG4gICAgICAgIGlmIChFTlZfREVCVUcpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZygncGFyZW50IGRvZXMgbm90IGhhdmUnLCB7W2tleV06IHZhbHVlfSlcbiAgICAgICAgfVxuICAgICAgICBzZXRDaG9zZW4oa2V5LCB2YWx1ZSlcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKGxldCBrID0gMCwgbGVuID0ga2V5cy5sZW5ndGg7IGsgPCBsZW47IGsrKykge1xuICAgICAgLy8ga2V5IHRvIHRoZSBjdXJyZW50IHByb3BlcnR5IGluIHRoZSBkYXRhIGJlaW5nIG1lcmdlZFxuICAgICAgbGV0IGtleSA9IGtleXNba11cblxuICAgICAgLy8gd2UgaGF2ZSBvdXIgdmFsdWUsIG5vIHdlIGNhbiBjaGFuZ2UgdGhlIGtleSBpZiBuZWVkZWQgZm9yIHNob3J0aGFuZHNcbiAgICAgIGNvbnN0IHZhbHVlID0gb2JqW2tleV1cblxuICAgICAgLy8gQE5PVEU6IHdoZW4gc2hvcnRoYW5kcyBpcyBhbiBvYmplY3QsIGtleSBpcyB0aGUgbWV0aG9kIGl0IHNob3VsZCBjYWxsXG4gICAgICBpZiAoIWlzVW5kZWZpbmVkKHNob3J0aGFuZHNba2V5XSkgJiYgc2hvcnRoYW5kc1trZXldICE9PSBrZXkpIHtcbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQ6IGRldnMgKi9cbiAgICAgICAgaWYgKEVOVl9ERUJVRykge1xuICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgJ2hhZCBhIHNob3J0aGFuZCB3aXRoIGEgZGlmZiBrZXkgdGhhbiB0aGUgb2JqZWN0IChsaWtlbHkgQGFsaWFzKScsXG4gICAgICAgICAgICB7c2hvcnRoYW5kTWV0aG9kOiBzaG9ydGhhbmRzW2tleV0sIGtleSwgdmFsdWV9XG4gICAgICAgICAgKVxuICAgICAgICB9XG4gICAgICAgIGtleSA9IHNob3J0aGFuZHNba2V5XVxuICAgICAgfVxuXG4gICAgICAvLyBtZXRob2QgZm9yIHRoZSBrZXlcbiAgICAgIGNvbnN0IG1ldGhvZCA9IHBhcmVudFtrZXldXG5cbiAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBzb3VyY2VtYXBzIHRyaWdnZXIgaXN0YW5idWwgaGVyZSBpbmNvcnJlY3RseSAqL1xuICAgICAgLy8gdXNlIG9uVmFsdWUgd2hlbiBzZXRcbiAgICAgIGlmICghb25WYWx1ZSh2YWx1ZSwga2V5LCB0aGlzKSkge1xuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dDogZGV2cyAqL1xuICAgICAgICBpZiAoRU5WX0RFQlVHKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coJ2hhZCBvblZhbHVlLCB3YXMgZmFsc2UsIGlnbm9yZWQnLCB7b25WYWx1ZSwga2V5LCB2YWx1ZX0pXG4gICAgICAgIH1cbiAgICAgICAgY29udGludWVcbiAgICAgIH1cbiAgICAgIC8vIHdoZW4gcHJvcGVydHkgaXRzZWxmIGlzIGEgQ2hhaW5hYmxlXG4gICAgICBlbHNlIGlmIChpc01hcGlzaChtZXRob2QpKSB7XG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBkZXZzICovXG4gICAgICAgIGlmIChFTlZfREVCVUcpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZygnaGFzIG1ldGhvZCBvciBzaG9ydGhhbmQnKVxuICAgICAgICB9XG4gICAgICAgIHBhcmVudFtrZXldLm1lcmdlKHZhbHVlKVxuICAgICAgfVxuICAgICAgLy8gd2UgaGF2ZSBhIG1ldGhvZCBvciBzaG9ydGhhbmRcbiAgICAgIGVsc2UgaWYgKG1ldGhvZCkge1xuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dDogZGV2cyAqL1xuICAgICAgICBpZiAoRU5WX0RFQlVHKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coJ2hhcyBtZXRob2Qgb3Igc2hvcnRoYW5kJywge21ldGhvZCwga2V5LCB2YWx1ZX0pXG4gICAgICAgIH1cbiAgICAgICAgaGFuZGxlRXhpc3Rpbmcoa2V5LCB2YWx1ZSlcbiAgICAgIH1cbiAgICAgIC8vIGRlZmF1bHQgdG8gLnNldCBvbiB0aGUgc3RvcmVcbiAgICAgIGVsc2Uge1xuICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dDogZGV2cyAqL1xuICAgICAgICBpZiAoRU5WX0RFQlVHKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coJ3dlbnQgdG8gZGVmYXVsdCcsIHttZXRob2QsIGtleSwgdmFsdWV9KVxuICAgICAgICB9XG4gICAgICAgIHBhcmVudC5zZXQoa2V5LCB2YWx1ZSlcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcGFyZW50XG4gIH1cbn1cblxuLyoqXG4gKiBAbWVtYmVyT2YgTWVyZ2VDaGFpblxuICogQG1ldGhvZCBvbkV4aXN0aW5nXG4gKiBAc2luY2UgMC45LjBcbiAqIEBleGFtcGxlXG4gKiAgICBjb25zdCB7Q2hhaW4sIE1lcmdlQ2hhaW59ID0gcmVxdWlyZSgnY2hhaW4tYWJsZScpXG4gKlxuICogICAgY29uc3QgY2hhaW4gPSBuZXcgQ2hhaW4oKS5zZXQoJ3N0cicsICdzdHJpbmd5JylcbiAqXG4gKiAgICBNZXJnZUNoYWluLmluaXQoY2hhaW4pXG4gKiAgICAgIC5vbkV4aXN0aW5nKChhLCBiKSA9PiBhICsgYilcbiAqICAgICAgLm1lcmdlKHtzdHI6ICcrJ30pXG4gKlxuICogICAgY2hhaW4uZ2V0KCdzdHInKVxuICogICAgLy89PiAnc3RyaW5neSsnXG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSBNZXJnZUNoYWluXG5cbi8vIEBUT0RPIHJlLWVuYWJsZSB0aGlzIGxhdGVyXG4vLyBtb2R1bGUuZXhwb3J0cyA9IG5ldyBNZXRob2RDaGFpbihNZXJnZUNoYWluLnByb3RvdHlwZSlcbi8vICAgLm1ldGhvZHMoWydvbkV4aXN0aW5nJywgJ29uVmFsdWUnLCAnb2JqJ10pXG4vLyAgIC5idWlsZChNZXJnZUNoYWluKVxuIl0sIm5hbWVzIjpbImNvbnN0Iiwic3VwZXIiLCJ0aGlzIiwibGV0Il0sIm1hcHBpbmdzIjoiQUFBQTtBQUNBQSxHQUFLLENBQUMsV0FBVyxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUM7QUFDNUNBLEdBQUssQ0FBQyxjQUFjLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixDQUFDO0FBQ2xEQSxHQUFLLENBQUMsU0FBUyxHQUFHLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztBQUM3Q0EsR0FBSyxDQUFDLFVBQVUsR0FBRyxPQUFPLENBQUMsb0JBQW9CLENBQUM7QUFDaERBLEdBQUssQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFDLHFCQUFxQixDQUFDO0FBQ2xEQSxHQUFLLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQztBQUN4Q0EsR0FBSyxDQUFDLFFBQVEsR0FBRyxPQUFPLENBQUMsa0JBQWtCLENBQUM7QUFDNUNBLEdBQUssQ0FBQyxVQUFVLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixDQUFDO0FBQzlDQSxHQUFLLENBQUMsY0FBYyxHQUFHLE9BQU8sQ0FBQyx3QkFBd0IsQ0FBQztBQUN4REEsR0FBSyxDQUFDLGVBQWUsR0FBRyxPQUFPLENBQUMsZ0JBQWdCLENBQUM7QUFDakRBLEdBQUssQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixDQUFDOztBQUU3Q0EsR0FBSyxDQUFDLGVBQWUsR0FBRyxZQUFZO0FBQ3BDQSxHQUFLLENBQUMsWUFBWSxHQUFHLFNBQVM7QUFDOUJBLEdBQUssQ0FBQyxVQUFVLEdBQUcsUUFBUTtBQUMzQkEsR0FBSyxDQUFDLGtCQUFrQixHQUFHLE1BQU07QUFDakNBLEdBQUssQ0FBQyxPQUFPLEdBQUcsS0FBSzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQW1CckIsSUFBTSxVQUFV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