foop
Version:
interfaces that describe their intentions.
264 lines (239 loc) • 19.6 kB
JavaScript
var ENV_DEBUG = require('./deps/env/debug')
var ChainedMap = require('./ChainedMap')
var isUndefined = require('./deps/is/undefined')
var isTrue = require('./deps/is/true')
var newSet = require('./deps/construct/set')
var ON_CHAIN_UP_DOWN_KEY = 'onChainUpDown'
var ON_DONE_KEY = 'onDone'
/**
* @extends {ChainedMapBase}
* @inheritdoc
*
* @since 1.0.0
*
* @prop {Object} data
* @prop {Set} _calls
* @type {Map}
*
* {@link http://robdodson.me/javascript-design-patterns-factory/ abstract-factory-pattern}
* @see {@link abstract-factory-pattern}
*
* @member FactoryChain
* @category Chainable
*
* @tests FactoryChain
* @types FactoryChain
*/
var FactoryChain = (function (ChainedMap) {
function FactoryChain(parent) {
ChainedMap.call(this, parent)
this.data = {}
this._calls = new Set()
this.factory()
.extend(['optional', 'required', ON_CHAIN_UP_DOWN_KEY, ON_DONE_KEY])
.set('len', 0)
}
if ( ChainedMap ) FactoryChain.__proto__ = ChainedMap;
FactoryChain.prototype = Object.create( ChainedMap && ChainedMap.prototype );
FactoryChain.prototype.constructor = FactoryChain;
/**
* @desc chain back up to parent for any of these
* @since 2.0.0
*
* @param {Array<string>} methods methods to trigger `onChainUpDown` on
* @return {FactoryChain} @chainable
*
* @memberOf FactoryChain
* @emits onChainUpDown
* @TODO should have a debug log for this
*
* @example
*
* const {Chain, FactoryChain, ChainedSet} = require('chain-able')
*
* class Things extends Chain {
* constructor(parent) {
* super(parent)
* this.people = new ChainedSet(this)
* }
* person() {
* const person = new FactoryChain(this)
* person
* .props(['name', 'age', 'email'])
* .onChainUpDown(this.person)
* .chainUpDowns(['person'])
* .onDone(personChain => {
* this.people.add(personChain)
* return this
* })
*
* return person
* }
* }
*
* const things = new Things()
* const returned = things
* .person()
* .name('sue')
* .person()
* .age(100)
* .name('john')
* .email('@')
*
*/
FactoryChain.prototype.chainUpDowns = function chainUpDowns (methods) {
var arguments$1 = arguments;
var this$1 = this;
methods.forEach(function (m) {
this$1[m] = function () {
// @@debugger
this$1.end()
return this$1.parent[m].apply(this$1.parent, arguments$1)
}
})
return this
};
/**
* @desc adds an *array* of properties, using FactoryChain.prop
* @since 2.0.0
*
* @memberOf FactoryChain
* @param {Array<string>} names property names
* @return {FactoryChain} @chainable
*
* @see FactoryChain.prop
*
* @example
*
* person.props(['name', 'age', 'email'])
*
* typeof person.name
* //=> 'function'
*
* person.name().age()
* //=> FactoryChain
*
* person.name().age().email()
* //=> ParentChain
*
* // person.name().age().person()
* //=> FactoryChain
* //^ because .person is `chainUpDowns`
* //^ so it finishes the old chain, and begins a new one
*
*/
FactoryChain.prototype.props = function props (names) {
var this$1 = this;
names.forEach(function (name) { return this$1.prop(name); })
return this
};
/* istanbul ignore next: sourcemaps trigger istanbul here incorrectly */
/**
* @desc add property that are counted towards the call count for easy auto-ending chaining
* @since 2.0.0
*
* @param {Primitive} name property name
* @param {Function | null | undefined} [onCall=undefined] callback for the property
* @return {FactoryChain} @chainable
*
* @memberOf FactoryChain
*
* @example
*
* person
* //.prop also accepts an optional callback,
* //for nestable nestable chains
* .prop('name')
* .prop('age')
* .prop('email')
*
*/
FactoryChain.prototype.prop = function prop (name, onCall) {
var this$1 = this;
this.tap('len', function (len) { return len + 1; })
// so if we call a property twice,
// chain back up to parent,
// add a new chain
if (!isUndefined(this[name]) && isTrue(this.has(ON_CHAIN_UP_DOWN_KEY))) {
this.end()
return this.get(ON_CHAIN_UP_DOWN_KEY)()[name](onCall)
}
// @TODO need to spread as needed
this[name] = function (args) {
// @@debugger
/* istanbul ignore next: devs */
if (ENV_DEBUG) {
console.log(
("called " + name + " with:"),
args,
"calls length is now:",
this$1._calls.size
)
}
if (isUndefined(onCall)) { this$1.data[name] = args }
else { onCall(args) }
this$1._calls.add(name)
// aka magicReturn
return this$1._calls.size === this$1.get('len') ? this$1.end() : this$1
}
return this
};
/**
* @desc access data being built when stepping through a factory
* @since 2.0.0
*
* @param {Primitive} [prop=undefined] key of the data, or returns all data
* @return {any} this.data
*
* @memberOf FactoryChain
*
* @example
*
* .data['prop'] = 'eh'
* .getData('prop')
* //=> 'eh'
* .getData()
* //=> {prop: 'eh'}
*
* @example
*
* const person = new FactoryChain(this)
* const age = person.props(['name', 'age']).age(10).getData('age')
* expect(age).toBe(10)
*
*/
FactoryChain.prototype.getData = function getData (prop) {
/* istanbul ignore next: sourcemaps trigger istanbul here incorrectly */
return isUndefined(prop) ? this.data : this.data[prop]
};
/* istanbul ignore next: sourcemaps trigger istanbul here incorrectly */
/**
* @desc creates/add the `.end` method,
* which checks how many methods have been called,
* and decides whether to return parent or not
* @modifies this.end
*
* @since 2.0.0
*
* @param {Object} [obj={}] optional object to use for creating .end
* @return {FactoryChain} @chainable
*
* @memberOf FactoryChain
*/
FactoryChain.prototype.factory = function factory (obj) {
var this$1 = this;
this.end = function (arg) {
// @@debugger
var ended
if (obj && !isUndefined(obj.end)) { ended = obj.end }
else if (this$1.has(ON_DONE_KEY)) { ended = this$1.get(ON_DONE_KEY) }
if (ended) { ended = ended.call(this$1, this$1.data, this$1.parent, this$1, arg) }
if (ended && ended !== this$1) { return ended }
else { return this$1.parent }
}
return this
};
return FactoryChain;
}(ChainedMap));
module.exports = FactoryChain
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmFjdG9yeUNoYWluLmpzIiwic291cmNlcyI6WyJGYWN0b3J5Q2hhaW4uanMiXSwic291cmNlc0NvbnRlbnQiOlsiY29uc3QgRU5WX0RFQlVHID0gcmVxdWlyZSgnLi9kZXBzL2Vudi9kZWJ1ZycpXG5jb25zdCBDaGFpbmVkTWFwID0gcmVxdWlyZSgnLi9DaGFpbmVkTWFwJylcbmNvbnN0IGlzVW5kZWZpbmVkID0gcmVxdWlyZSgnLi9kZXBzL2lzL3VuZGVmaW5lZCcpXG5jb25zdCBpc1RydWUgPSByZXF1aXJlKCcuL2RlcHMvaXMvdHJ1ZScpXG5jb25zdCBuZXdTZXQgPSByZXF1aXJlKCcuL2RlcHMvY29uc3RydWN0L3NldCcpXG5cbmNvbnN0IE9OX0NIQUlOX1VQX0RPV05fS0VZID0gJ29uQ2hhaW5VcERvd24nXG5jb25zdCBPTl9ET05FX0tFWSA9ICdvbkRvbmUnXG5cbi8qKlxuICogQGV4dGVuZHMge0NoYWluZWRNYXBCYXNlfVxuICogQGluaGVyaXRkb2NcbiAqXG4gKiBAc2luY2UgMS4wLjBcbiAqXG4gKiBAcHJvcCB7T2JqZWN0fSBkYXRhXG4gKiBAcHJvcCB7U2V0fSBfY2FsbHNcbiAqIEB0eXBlIHtNYXB9XG4gKlxuICoge0BsaW5rIGh0dHA6Ly9yb2Jkb2Rzb24ubWUvamF2YXNjcmlwdC1kZXNpZ24tcGF0dGVybnMtZmFjdG9yeS8gYWJzdHJhY3QtZmFjdG9yeS1wYXR0ZXJufVxuICogQHNlZSB7QGxpbmsgYWJzdHJhY3QtZmFjdG9yeS1wYXR0ZXJufVxuICpcbiAqIEBtZW1iZXIgRmFjdG9yeUNoYWluXG4gKiBAY2F0ZWdvcnkgQ2hhaW5hYmxlXG4gKlxuICogQHRlc3RzIEZhY3RvcnlDaGFpblxuICogQHR5cGVzIEZhY3RvcnlDaGFpblxuICovXG5jbGFzcyBGYWN0b3J5Q2hhaW4gZXh0ZW5kcyBDaGFpbmVkTWFwIHtcbiAgY29uc3RydWN0b3IocGFyZW50KSB7XG4gICAgc3VwZXIocGFyZW50KVxuXG4gICAgdGhpcy5kYXRhID0ge31cbiAgICB0aGlzLl9jYWxscyA9IG5ldyBTZXQoKVxuXG4gICAgdGhpcy5mYWN0b3J5KClcbiAgICAgIC5leHRlbmQoWydvcHRpb25hbCcsICdyZXF1aXJlZCcsIE9OX0NIQUlOX1VQX0RPV05fS0VZLCBPTl9ET05FX0tFWV0pXG4gICAgICAuc2V0KCdsZW4nLCAwKVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjIGNoYWluIGJhY2sgdXAgdG8gcGFyZW50IGZvciBhbnkgb2YgdGhlc2VcbiAgICogQHNpbmNlIDIuMC4wXG4gICAqXG4gICAqIEBwYXJhbSAge0FycmF5PHN0cmluZz59IG1ldGhvZHMgbWV0aG9kcyB0byB0cmlnZ2VyIGBvbkNoYWluVXBEb3duYCBvblxuICAgKiBAcmV0dXJuIHtGYWN0b3J5Q2hhaW59IEBjaGFpbmFibGVcbiAgICpcbiAgICogQG1lbWJlck9mIEZhY3RvcnlDaGFpblxuICAgKiBAZW1pdHMgb25DaGFpblVwRG93blxuICAgKiBAVE9ETyBzaG91bGQgaGF2ZSBhIGRlYnVnIGxvZyBmb3IgdGhpc1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICBjb25zdCB7Q2hhaW4sIEZhY3RvcnlDaGFpbiwgQ2hhaW5lZFNldH0gPSByZXF1aXJlKCdjaGFpbi1hYmxlJylcbiAgICpcbiAgICogICAgY2xhc3MgVGhpbmdzIGV4dGVuZHMgQ2hhaW4ge1xuICAgKiAgICAgIGNvbnN0cnVjdG9yKHBhcmVudCkge1xuICAgKiAgICAgICAgc3VwZXIocGFyZW50KVxuICAgKiAgICAgICAgdGhpcy5wZW9wbGUgPSBuZXcgQ2hhaW5lZFNldCh0aGlzKVxuICAgKiAgICAgIH1cbiAgICogICAgICBwZXJzb24oKSB7XG4gICAqICAgICAgICBjb25zdCBwZXJzb24gPSBuZXcgRmFjdG9yeUNoYWluKHRoaXMpXG4gICAqICAgICAgICBwZXJzb25cbiAgICogICAgICAgICAgLnByb3BzKFsnbmFtZScsICdhZ2UnLCAnZW1haWwnXSlcbiAgICogICAgICAgICAgLm9uQ2hhaW5VcERvd24odGhpcy5wZXJzb24pXG4gICAqICAgICAgICAgIC5jaGFpblVwRG93bnMoWydwZXJzb24nXSlcbiAgICogICAgICAgICAgLm9uRG9uZShwZXJzb25DaGFpbiA9PiB7XG4gICAqICAgICAgICAgICAgdGhpcy5wZW9wbGUuYWRkKHBlcnNvbkNoYWluKVxuICAgKiAgICAgICAgICAgIHJldHVybiB0aGlzXG4gICAqICAgICAgICAgIH0pXG4gICAqXG4gICAqICAgICAgICByZXR1cm4gcGVyc29uXG4gICAqICAgICAgfVxuICAgKiAgICB9XG4gICAqXG4gICAqICAgIGNvbnN0IHRoaW5ncyA9IG5ldyBUaGluZ3MoKVxuICAgKiAgICBjb25zdCByZXR1cm5lZCA9IHRoaW5nc1xuICAgKiAgICAgICAgLnBlcnNvbigpXG4gICAqICAgICAgICAgIC5uYW1lKCdzdWUnKVxuICAgKiAgICAgICAgLnBlcnNvbigpXG4gICAqICAgICAgICAgIC5hZ2UoMTAwKVxuICAgKiAgICAgICAgICAubmFtZSgnam9obicpXG4gICAqICAgICAgICAgIC5lbWFpbCgnQCcpXG4gICAqXG4gICAqL1xuICBjaGFpblVwRG93bnMobWV0aG9kcykge1xuICAgIG1ldGhvZHMuZm9yRWFjaChtID0+IHtcbiAgICAgIHRoaXNbbV0gPSAoKSA9PiB7XG4gICAgICAgIC8vIEBAZGVidWdnZXJcbiAgICAgICAgdGhpcy5lbmQoKVxuICAgICAgICByZXR1cm4gdGhpcy5wYXJlbnRbbV0uYXBwbHkodGhpcy5wYXJlbnQsIGFyZ3VtZW50cylcbiAgICAgIH1cbiAgICB9KVxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICAvKipcbiAgICogQGRlc2MgYWRkcyBhbiAqYXJyYXkqIG9mIHByb3BlcnRpZXMsIHVzaW5nIEZhY3RvcnlDaGFpbi5wcm9wXG4gICAqIEBzaW5jZSAyLjAuMFxuICAgKlxuICAgKiBAbWVtYmVyT2YgRmFjdG9yeUNoYWluXG4gICAqIEBwYXJhbSAge0FycmF5PHN0cmluZz59IG5hbWVzIHByb3BlcnR5IG5hbWVzXG4gICAqIEByZXR1cm4ge0ZhY3RvcnlDaGFpbn0gQGNoYWluYWJsZVxuICAgKlxuICAgKiBAc2VlIEZhY3RvcnlDaGFpbi5wcm9wXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgIHBlcnNvbi5wcm9wcyhbJ25hbWUnLCAnYWdlJywgJ2VtYWlsJ10pXG4gICAqXG4gICAqICAgIHR5cGVvZiBwZXJzb24ubmFtZVxuICAgKiAgICAvLz0+ICdmdW5jdGlvbidcbiAgICpcbiAgICogICAgcGVyc29uLm5hbWUoKS5hZ2UoKVxuICAgKiAgICAvLz0+IEZhY3RvcnlDaGFpblxuICAgKlxuICAgKiAgICBwZXJzb24ubmFtZSgpLmFnZSgpLmVtYWlsKClcbiAgICogICAgLy89PiBQYXJlbnRDaGFpblxuICAgKlxuICAgKiAgICAvLyBwZXJzb24ubmFtZSgpLmFnZSgpLnBlcnNvbigpXG4gICAqICAgIC8vPT4gRmFjdG9yeUNoYWluXG4gICAqICAgIC8vXiBiZWNhdXNlIC5wZXJzb24gaXMgYGNoYWluVXBEb3duc2BcbiAgICogICAgLy9eIHNvIGl0IGZpbmlzaGVzIHRoZSBvbGQgY2hhaW4sIGFuZCBiZWdpbnMgYSBuZXcgb25lXG4gICAqXG4gICAqL1xuICBwcm9wcyhuYW1lcykge1xuICAgIG5hbWVzLmZvckVhY2gobmFtZSA9PiB0aGlzLnByb3AobmFtZSkpXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG4gIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBzb3VyY2VtYXBzIHRyaWdnZXIgaXN0YW5idWwgaGVyZSBpbmNvcnJlY3RseSAqL1xuICAvKipcbiAgICogQGRlc2MgYWRkIHByb3BlcnR5IHRoYXQgYXJlIGNvdW50ZWQgdG93YXJkcyB0aGUgY2FsbCBjb3VudCBmb3IgZWFzeSBhdXRvLWVuZGluZyBjaGFpbmluZ1xuICAgKiBAc2luY2UgMi4wLjBcbiAgICpcbiAgICogQHBhcmFtICB7UHJpbWl0aXZlfSBuYW1lIHByb3BlcnR5IG5hbWVcbiAgICogQHBhcmFtICB7RnVuY3Rpb24gfCBudWxsIHwgdW5kZWZpbmVkfSBbb25DYWxsPXVuZGVmaW5lZF0gY2FsbGJhY2sgZm9yIHRoZSBwcm9wZXJ0eVxuICAgKiBAcmV0dXJuIHtGYWN0b3J5Q2hhaW59IEBjaGFpbmFibGVcbiAgICpcbiAgICogQG1lbWJlck9mIEZhY3RvcnlDaGFpblxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICBwZXJzb25cbiAgICogICAgICAvLy5wcm9wIGFsc28gYWNjZXB0cyBhbiBvcHRpb25hbCBjYWxsYmFjayxcbiAgICogICAgICAvL2ZvciBuZXN0YWJsZSBuZXN0YWJsZSBjaGFpbnNcbiAgICogICAgICAucHJvcCgnbmFtZScpXG4gICAqICAgICAgLnByb3AoJ2FnZScpXG4gICAqICAgICAgLnByb3AoJ2VtYWlsJylcbiAgICpcbiAgICovXG4gIHByb3AobmFtZSwgb25DYWxsKSB7XG4gICAgdGhpcy50YXAoJ2xlbicsIGxlbiA9PiBsZW4gKyAxKVxuXG4gICAgLy8gc28gaWYgd2UgY2FsbCBhIHByb3BlcnR5IHR3aWNlLFxuICAgIC8vIGNoYWluIGJhY2sgdXAgdG8gcGFyZW50LFxuICAgIC8vIGFkZCBhIG5ldyBjaGFpblxuICAgIGlmICghaXNVbmRlZmluZWQodGhpc1tuYW1lXSkgJiYgaXNUcnVlKHRoaXMuaGFzKE9OX0NIQUlOX1VQX0RPV05fS0VZKSkpIHtcbiAgICAgIHRoaXMuZW5kKClcbiAgICAgIHJldHVybiB0aGlzLmdldChPTl9DSEFJTl9VUF9ET1dOX0tFWSkoKVtuYW1lXShvbkNhbGwpXG4gICAgfVxuXG4gICAgLy8gQFRPRE8gbmVlZCB0byBzcHJlYWQgYXMgbmVlZGVkXG4gICAgdGhpc1tuYW1lXSA9IGFyZ3MgPT4ge1xuICAgICAgLy8gQEBkZWJ1Z2dlclxuICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQ6IGRldnMgKi9cbiAgICAgIGlmIChFTlZfREVCVUcpIHtcbiAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgYGNhbGxlZCAke25hbWV9IHdpdGg6YCxcbiAgICAgICAgICBhcmdzLFxuICAgICAgICAgIGBjYWxscyBsZW5ndGggaXMgbm93OmAsXG4gICAgICAgICAgdGhpcy5fY2FsbHMuc2l6ZVxuICAgICAgICApXG4gICAgICB9XG4gICAgICBpZiAoaXNVbmRlZmluZWQob25DYWxsKSkgdGhpcy5kYXRhW25hbWVdID0gYXJnc1xuICAgICAgZWxzZSBvbkNhbGwoYXJncylcblxuICAgICAgdGhpcy5fY2FsbHMuYWRkKG5hbWUpXG5cbiAgICAgIC8vIGFrYSBtYWdpY1JldHVyblxuICAgICAgcmV0dXJuIHRoaXMuX2NhbGxzLnNpemUgPT09IHRoaXMuZ2V0KCdsZW4nKSA/IHRoaXMuZW5kKCkgOiB0aGlzXG4gICAgfVxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICAvKipcbiAgICogQGRlc2MgYWNjZXNzIGRhdGEgYmVpbmcgYnVpbHQgd2hlbiBzdGVwcGluZyB0aHJvdWdoIGEgZmFjdG9yeVxuICAgKiBAc2luY2UgMi4wLjBcbiAgICpcbiAgICogQHBhcmFtICB7UHJpbWl0aXZlfSBbcHJvcD11bmRlZmluZWRdIGtleSBvZiB0aGUgZGF0YSwgb3IgcmV0dXJucyBhbGwgZGF0YVxuICAgKiBAcmV0dXJuIHthbnl9IHRoaXMuZGF0YVxuICAgKlxuICAgKiBAbWVtYmVyT2YgRmFjdG9yeUNoYWluXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgIC5kYXRhWydwcm9wJ10gPSAnZWgnXG4gICAqICAgIC5nZXREYXRhKCdwcm9wJylcbiAgICogICAgLy89PiAnZWgnXG4gICAqICAgIC5nZXREYXRhKClcbiAgICogICAgLy89PiB7cHJvcDogJ2VoJ31cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgY29uc3QgcGVyc29uID0gbmV3IEZhY3RvcnlDaGFpbih0aGlzKVxuICAgKiAgICBjb25zdCBhZ2UgPSBwZXJzb24ucHJvcHMoWyduYW1lJywgJ2FnZSddKS5hZ2UoMTApLmdldERhdGEoJ2FnZScpXG4gICAqICAgIGV4cGVjdChhZ2UpLnRvQmUoMTApXG4gICAqXG4gICAqL1xuICBnZXREYXRhKHByb3ApIHtcbiAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dDogc291cmNlbWFwcyB0cmlnZ2VyIGlzdGFuYnVsIGhlcmUgaW5jb3JyZWN0bHkgKi9cbiAgICByZXR1cm4gaXNVbmRlZmluZWQocHJvcCkgPyB0aGlzLmRhdGEgOiB0aGlzLmRhdGFbcHJvcF1cbiAgfVxuXG4gIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBzb3VyY2VtYXBzIHRyaWdnZXIgaXN0YW5idWwgaGVyZSBpbmNvcnJlY3RseSAqL1xuICAvKipcbiAgICogQGRlc2MgY3JlYXRlcy9hZGQgdGhlIGAuZW5kYCBtZXRob2QsXG4gICAqICAgICAgIHdoaWNoIGNoZWNrcyBob3cgbWFueSBtZXRob2RzIGhhdmUgYmVlbiBjYWxsZWQsXG4gICAqICAgICAgIGFuZCBkZWNpZGVzIHdoZXRoZXIgdG8gcmV0dXJuIHBhcmVudCBvciBub3RcbiAgICogICAgICAgQG1vZGlmaWVzIHRoaXMuZW5kXG4gICAqXG4gICAqIEBzaW5jZSAyLjAuMFxuICAgKlxuICAgKiBAcGFyYW0gIHtPYmplY3R9IFtvYmo9e31dIG9wdGlvbmFsIG9iamVjdCB0byB1c2UgZm9yIGNyZWF0aW5nIC5lbmRcbiAgICogQHJldHVybiB7RmFjdG9yeUNoYWlufSBAY2hhaW5hYmxlXG4gICAqXG4gICAqIEBtZW1iZXJPZiBGYWN0b3J5Q2hhaW5cbiAgICovXG4gIGZhY3Rvcnkob2JqKSB7XG4gICAgdGhpcy5lbmQgPSBhcmcgPT4ge1xuICAgICAgLy8gQEBkZWJ1Z2dlclxuICAgICAgbGV0IGVuZGVkXG5cbiAgICAgIGlmIChvYmogJiYgIWlzVW5kZWZpbmVkKG9iai5lbmQpKSBlbmRlZCA9IG9iai5lbmRcbiAgICAgIGVsc2UgaWYgKHRoaXMuaGFzKE9OX0RPTkVfS0VZKSkgZW5kZWQgPSB0aGlzLmdldChPTl9ET05FX0tFWSlcblxuICAgICAgaWYgKGVuZGVkKSBlbmRlZCA9IGVuZGVkLmNhbGwodGhpcywgdGhpcy5kYXRhLCB0aGlzLnBhcmVudCwgdGhpcywgYXJnKVxuXG4gICAgICBpZiAoZW5kZWQgJiYgZW5kZWQgIT09IHRoaXMpIHJldHVybiBlbmRlZFxuICAgICAgZWxzZSByZXR1cm4gdGhpcy5wYXJlbnRcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpc1xuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gRmFjdG9yeUNoYWluXG4iXSwibmFtZXMiOlsiY29uc3QiLCJzdXBlciIsInRoaXMiLCJhcmd1bWVudHMiLCJsZXQiXSwibWFwcGluZ3MiOiJBQUFBQSxHQUFLLENBQUMsU0FBUyxHQUFHLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztBQUM3Q0EsR0FBSyxDQUFDLFVBQVUsR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDO0FBQzFDQSxHQUFLLENBQUMsV0FBVyxHQUFHLE9BQU8sQ0FBQyxxQkFBcUIsQ0FBQztBQUNsREEsR0FBSyxDQUFDLE1BQU0sR0FBRyxPQUFPLENBQUMsZ0JBQWdCLENBQUM7QUFDeENBLEdBQUssQ0FBQyxNQUFNLEdBQUcsT0FBTyxDQUFDLHNCQUFzQixDQUFDOztBQUU5Q0EsR0FBSyxDQUFDLG9CQUFvQixHQUFHLGVBQWU7QUFDNUNBLEdBQUssQ0FBQyxXQUFXLEdBQUcsUUFBUTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBcUI1QixJQUFNLFlBQVksR0FBbUI7RUFBQyxBQUNwQyxxQkFBVyxDQUFDLE1BQU0sRUFBRTtJQUNsQkMsVUFBSyxLQUFBLENBQUMsTUFBQSxNQUFNLENBQUM7O0lBRWIsSUFBSSxDQUFDLElBQUksR0FBRyxFQUFFO0lBQ2QsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBRTs7SUFFdkIsSUFBSSxDQUFDLE9BQU8sRUFBRTtPQUNYLE1BQU0sQ0FBQyxDQUFDLFVBQVUsRUFBRSxVQUFVLEVBQUUsb0JBQW9CLEVBQUUsV0FBVyxDQUFDLENBQUM7T0FDbkUsR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7R0FDakI7Ozs7b0RBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0VBK0NELHVCQUFBLFlBQVkseUJBQUEsQ0FBQyxPQUFPLEVBQUUsQ0FBQzs7O0FBQUE7SUFDckIsT0FBTyxDQUFDLE9BQU8sQ0FBQyxVQUFBLENBQUMsQ0FBQSxDQUFDLEFBQUc7TUFDbkJDLE1BQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxTQUFBLEdBQUcsQUFBRzs7UUFFZEEsTUFBSSxDQUFDLEdBQUcsRUFBRTtRQUNWLE9BQU9BLE1BQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDQSxNQUFJLENBQUMsTUFBTSxFQUFFQyxXQUFTLENBQUM7T0FDcEQ7S0FDRixDQUFDO0lBQ0YsT0FBTyxJQUFJO0dBQ1osQ0FBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQStCRCx1QkFBQSxLQUFLLGtCQUFBLENBQUMsS0FBSyxFQUFFLENBQUM7O0FBQUE7SUFDWixLQUFLLENBQUMsT0FBTyxDQUFDLFVBQUEsSUFBSSxDQUFBLENBQUMsQUFBRyxTQUFBRCxNQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFBLENBQUM7SUFDdEMsT0FBTyxJQUFJO0dBQ1osQ0FBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7RUF1QkQsdUJBQUEsSUFBSSxpQkFBQSxDQUFDLElBQUksRUFBRSxNQUFNLEVBQUUsQ0FBQzs7QUFBQTtJQUNsQixJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxVQUFBLEdBQUcsQ0FBQSxDQUFDLEFBQUcsU0FBQSxHQUFHLEdBQUcsQ0FBQyxHQUFBLENBQUM7Ozs7O0lBSy9CLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxFQUFFO01BQ3RFLElBQUksQ0FBQyxHQUFHLEVBQUU7TUFDVixPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsb0JBQW9CLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sQ0FBQztLQUN0RDs7O0lBR0QsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLFVBQUEsSUFBSSxDQUFBLENBQUMsQUFBRzs7O01BR25CLElBQUksU0FBUyxFQUFFO1FBQ2IsT0FBTyxDQUFDLEdBQUc7VUFDVCxDQUFBLFNBQVEsR0FBRSxJQUFJLFdBQU8sQ0FBQztVQUN0QixJQUFJO1VBQ0osc0JBQXFCLEFBQUM7VUFDdEJBLE1BQUksQ0FBQyxNQUFNLENBQUMsSUFBSTtTQUNqQjtPQUNGO01BQ0QsSUFBSSxXQUFXLENBQUMsTUFBTSxDQUFDLEVBQUUsRUFBQUEsTUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLEVBQUE7V0FDMUMsRUFBQSxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUE7O01BRWpCQSxNQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUM7OztNQUdyQixPQUFPQSxNQUFJLENBQUMsTUFBTSxDQUFDLElBQUksS0FBS0EsTUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBR0EsTUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHQSxNQUFJO0tBQ2hFO0lBQ0QsT0FBTyxJQUFJO0dBQ1osQ0FBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7RUEwQkQsdUJBQUEsT0FBTyxvQkFBQSxDQUFDLElBQUksRUFBRTs7SUFFWixPQUFPLFdBQVcsQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO0dBQ3ZELENBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7RUFnQkQsdUJBQUEsT0FBTyxvQkFBQSxDQUFDLEdBQUcsRUFBRSxDQUFDOztBQUFBO0lBQ1osSUFBSSxDQUFDLEdBQUcsR0FBRyxVQUFBLEdBQUcsQ0FBQSxDQUFDLEFBQUc7O01BRWhCRSxHQUFHLENBQUMsS0FBSzs7TUFFVCxJQUFJLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBQSxLQUFLLEdBQUcsR0FBRyxDQUFDLEdBQUcsRUFBQTtXQUM1QyxJQUFJRixNQUFJLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUEsS0FBSyxHQUFHQSxNQUFJLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxFQUFBOztNQUU3RCxJQUFJLEtBQUssRUFBRSxFQUFBLEtBQUssR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDQSxNQUFJLEVBQUVBLE1BQUksQ0FBQyxJQUFJLEVBQUVBLE1BQUksQ0FBQyxNQUFNLEVBQUVBLE1BQUksRUFBRSxHQUFHLENBQUMsRUFBQTs7TUFFdEUsSUFBSSxLQUFLLElBQUksS0FBSyxLQUFLQSxNQUFJLEVBQUUsRUFBQSxPQUFPLEtBQUssRUFBQTtXQUNwQyxFQUFBLE9BQU9BLE1BQUksQ0FBQyxNQUFNLEVBQUE7S0FDeEI7O0lBRUQsT0FBTyxJQUFJO0dBQ1osQ0FBQSxBQUNGOzs7RUF4TjBCLFVBd04xQixHQUFBOztBQUVELE1BQU0sQ0FBQyxPQUFPLEdBQUcsWUFBWTsifQ==