chain-able
Version:
interfaces that describe their intentions.
256 lines (231 loc) • 19.2 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 ON_CHAIN_UP_DOWN_KEY = 'onChainUpDown'
var ON_DONE_KEY = 'onDone'
/**
* @extends {ChainedMapBase}
* @inheritdoc
* @prop {Object} data
* @prop {Set} _calls
* @type {Map}
*
* {@link http://robdodson.me/javascript-design-patterns-factory/ 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={}] optiona 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmFjdG9yeUNoYWluLmpzIiwic291cmNlcyI6WyJGYWN0b3J5Q2hhaW4uanMiXSwic291cmNlc0NvbnRlbnQiOlsiY29uc3QgRU5WX0RFQlVHID0gcmVxdWlyZSgnLi9kZXBzL2Vudi9kZWJ1ZycpXG5jb25zdCBDaGFpbmVkTWFwID0gcmVxdWlyZSgnLi9DaGFpbmVkTWFwJylcbmNvbnN0IGlzVW5kZWZpbmVkID0gcmVxdWlyZSgnLi9kZXBzL2lzL3VuZGVmaW5lZCcpXG5jb25zdCBpc1RydWUgPSByZXF1aXJlKCcuL2RlcHMvaXMvdHJ1ZScpXG5cbmNvbnN0IE9OX0NIQUlOX1VQX0RPV05fS0VZID0gJ29uQ2hhaW5VcERvd24nXG5jb25zdCBPTl9ET05FX0tFWSA9ICdvbkRvbmUnXG5cbi8qKlxuICogQGV4dGVuZHMge0NoYWluZWRNYXBCYXNlfVxuICogQGluaGVyaXRkb2NcbiAqIEBwcm9wIHtPYmplY3R9IGRhdGFcbiAqIEBwcm9wIHtTZXR9IF9jYWxsc1xuICogQHR5cGUge01hcH1cbiAqXG4gKiB7QGxpbmsgaHR0cDovL3JvYmRvZHNvbi5tZS9qYXZhc2NyaXB0LWRlc2lnbi1wYXR0ZXJucy1mYWN0b3J5LyBhYnN0cmFjdC1mYWN0b3J5LXBhdHRlcm59XG4gKlxuICogQG1lbWJlciBGYWN0b3J5Q2hhaW5cbiAqIEBjYXRlZ29yeSBDaGFpbmFibGVcbiAqIEB0ZXN0cyBGYWN0b3J5Q2hhaW5cbiAqIEB0eXBlcyBGYWN0b3J5Q2hhaW5cbiAqL1xuY2xhc3MgRmFjdG9yeUNoYWluIGV4dGVuZHMgQ2hhaW5lZE1hcCB7XG4gIGNvbnN0cnVjdG9yKHBhcmVudCkge1xuICAgIHN1cGVyKHBhcmVudClcblxuICAgIHRoaXMuZGF0YSA9IHt9XG4gICAgdGhpcy5fY2FsbHMgPSBuZXcgU2V0KClcblxuICAgIHRoaXMuZmFjdG9yeSgpXG4gICAgICAuZXh0ZW5kKFsnb3B0aW9uYWwnLCAncmVxdWlyZWQnLCBPTl9DSEFJTl9VUF9ET1dOX0tFWSwgT05fRE9ORV9LRVldKVxuICAgICAgLnNldCgnbGVuJywgMClcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzYyBjaGFpbiBiYWNrIHVwIHRvIHBhcmVudCBmb3IgYW55IG9mIHRoZXNlXG4gICAqIEBzaW5jZSAyLjAuMFxuICAgKlxuICAgKiBAcGFyYW0gIHtBcnJheTxzdHJpbmc+fSBtZXRob2RzIG1ldGhvZHMgdG8gdHJpZ2dlciBgb25DaGFpblVwRG93bmAgb25cbiAgICogQHJldHVybiB7RmFjdG9yeUNoYWlufSBAY2hhaW5hYmxlXG4gICAqXG4gICAqIEBtZW1iZXJPZiBGYWN0b3J5Q2hhaW5cbiAgICogQGVtaXRzIG9uQ2hhaW5VcERvd25cbiAgICogQFRPRE8gc2hvdWxkIGhhdmUgYSBkZWJ1ZyBsb2cgZm9yIHRoaXNcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgY29uc3Qge0NoYWluLCBGYWN0b3J5Q2hhaW4sIENoYWluZWRTZXR9ID0gcmVxdWlyZSgnY2hhaW4tYWJsZScpXG4gICAqXG4gICAqICAgIGNsYXNzIFRoaW5ncyBleHRlbmRzIENoYWluIHtcbiAgICogICAgICBjb25zdHJ1Y3RvcihwYXJlbnQpIHtcbiAgICogICAgICAgIHN1cGVyKHBhcmVudClcbiAgICogICAgICAgIHRoaXMucGVvcGxlID0gbmV3IENoYWluZWRTZXQodGhpcylcbiAgICogICAgICB9XG4gICAqICAgICAgcGVyc29uKCkge1xuICAgKiAgICAgICAgY29uc3QgcGVyc29uID0gbmV3IEZhY3RvcnlDaGFpbih0aGlzKVxuICAgKiAgICAgICAgcGVyc29uXG4gICAqICAgICAgICAgIC5wcm9wcyhbJ25hbWUnLCAnYWdlJywgJ2VtYWlsJ10pXG4gICAqICAgICAgICAgIC5vbkNoYWluVXBEb3duKHRoaXMucGVyc29uKVxuICAgKiAgICAgICAgICAuY2hhaW5VcERvd25zKFsncGVyc29uJ10pXG4gICAqICAgICAgICAgIC5vbkRvbmUocGVyc29uQ2hhaW4gPT4ge1xuICAgKiAgICAgICAgICAgIHRoaXMucGVvcGxlLmFkZChwZXJzb25DaGFpbilcbiAgICogICAgICAgICAgICByZXR1cm4gdGhpc1xuICAgKiAgICAgICAgICB9KVxuICAgKlxuICAgKiAgICAgICAgcmV0dXJuIHBlcnNvblxuICAgKiAgICAgIH1cbiAgICogICAgfVxuICAgKlxuICAgKiAgICBjb25zdCB0aGluZ3MgPSBuZXcgVGhpbmdzKClcbiAgICogICAgY29uc3QgcmV0dXJuZWQgPSB0aGluZ3NcbiAgICogICAgICAgIC5wZXJzb24oKVxuICAgKiAgICAgICAgICAubmFtZSgnc3VlJylcbiAgICogICAgICAgIC5wZXJzb24oKVxuICAgKiAgICAgICAgICAuYWdlKDEwMClcbiAgICogICAgICAgICAgLm5hbWUoJ2pvaG4nKVxuICAgKiAgICAgICAgICAuZW1haWwoJ0AnKVxuICAgKlxuICAgKi9cbiAgY2hhaW5VcERvd25zKG1ldGhvZHMpIHtcbiAgICBtZXRob2RzLmZvckVhY2gobSA9PiB7XG4gICAgICB0aGlzW21dID0gKCkgPT4ge1xuICAgICAgICAvLyBAQGRlYnVnZ2VyXG4gICAgICAgIHRoaXMuZW5kKClcbiAgICAgICAgcmV0dXJuIHRoaXMucGFyZW50W21dLmFwcGx5KHRoaXMucGFyZW50LCBhcmd1bWVudHMpXG4gICAgICB9XG4gICAgfSlcbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjIGFkZHMgYW4gKmFycmF5KiBvZiBwcm9wZXJ0aWVzLCB1c2luZyBGYWN0b3J5Q2hhaW4ucHJvcFxuICAgKiBAc2luY2UgMi4wLjBcbiAgICpcbiAgICogQG1lbWJlck9mIEZhY3RvcnlDaGFpblxuICAgKiBAcGFyYW0gIHtBcnJheTxzdHJpbmc+fSBuYW1lcyBwcm9wZXJ0eSBuYW1lc1xuICAgKiBAcmV0dXJuIHtGYWN0b3J5Q2hhaW59IEBjaGFpbmFibGVcbiAgICpcbiAgICogQHNlZSBGYWN0b3J5Q2hhaW4ucHJvcFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICBwZXJzb24ucHJvcHMoWyduYW1lJywgJ2FnZScsICdlbWFpbCddKVxuICAgKlxuICAgKiAgICB0eXBlb2YgcGVyc29uLm5hbWVcbiAgICogICAgLy89PiAnZnVuY3Rpb24nXG4gICAqXG4gICAqICAgIHBlcnNvbi5uYW1lKCkuYWdlKClcbiAgICogICAgLy89PiBGYWN0b3J5Q2hhaW5cbiAgICpcbiAgICogICAgcGVyc29uLm5hbWUoKS5hZ2UoKS5lbWFpbCgpXG4gICAqICAgIC8vPT4gUGFyZW50Q2hhaW5cbiAgICpcbiAgICogICAgLy8gcGVyc29uLm5hbWUoKS5hZ2UoKS5wZXJzb24oKVxuICAgKiAgICAvLz0+IEZhY3RvcnlDaGFpblxuICAgKiAgICAvL14gYmVjYXVzZSAucGVyc29uIGlzIGBjaGFpblVwRG93bnNgXG4gICAqICAgIC8vXiBzbyBpdCBmaW5pc2hlcyB0aGUgb2xkIGNoYWluLCBhbmQgYmVnaW5zIGEgbmV3IG9uZVxuICAgKlxuICAgKi9cbiAgcHJvcHMobmFtZXMpIHtcbiAgICBuYW1lcy5mb3JFYWNoKG5hbWUgPT4gdGhpcy5wcm9wKG5hbWUpKVxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dDogc291cmNlbWFwcyB0cmlnZ2VyIGlzdGFuYnVsIGhlcmUgaW5jb3JyZWN0bHkgKi9cbiAgLyoqXG4gICAqIEBkZXNjIGFkZCBwcm9wZXJ0eSB0aGF0IGFyZSBjb3VudGVkIHRvd2FyZHMgdGhlIGNhbGwgY291bnQgZm9yIGVhc3kgYXV0by1lbmRpbmcgY2hhaW5pbmdcbiAgICogQHNpbmNlIDIuMC4wXG4gICAqXG4gICAqIEBwYXJhbSAge1ByaW1pdGl2ZX0gbmFtZSBwcm9wZXJ0eSBuYW1lXG4gICAqIEBwYXJhbSAge0Z1bmN0aW9uIHwgbnVsbCB8IHVuZGVmaW5lZH0gW29uQ2FsbD11bmRlZmluZWRdIGNhbGxiYWNrIGZvciB0aGUgcHJvcGVydHlcbiAgICogQHJldHVybiB7RmFjdG9yeUNoYWlufSBAY2hhaW5hYmxlXG4gICAqXG4gICAqIEBtZW1iZXJPZiBGYWN0b3J5Q2hhaW5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgcGVyc29uXG4gICAqICAgICAgLy8ucHJvcCBhbHNvIGFjY2VwdHMgYW4gb3B0aW9uYWwgY2FsbGJhY2ssXG4gICAqICAgICAgLy9mb3IgbmVzdGFibGUgbmVzdGFibGUgY2hhaW5zXG4gICAqICAgICAgLnByb3AoJ25hbWUnKVxuICAgKiAgICAgIC5wcm9wKCdhZ2UnKVxuICAgKiAgICAgIC5wcm9wKCdlbWFpbCcpXG4gICAqXG4gICAqL1xuICBwcm9wKG5hbWUsIG9uQ2FsbCkge1xuICAgIHRoaXMudGFwKCdsZW4nLCBsZW4gPT4gbGVuICsgMSlcblxuICAgIC8vIHNvIGlmIHdlIGNhbGwgYSBwcm9wZXJ0eSB0d2ljZSxcbiAgICAvLyBjaGFpbiBiYWNrIHVwIHRvIHBhcmVudCxcbiAgICAvLyBhZGQgYSBuZXcgY2hhaW5cbiAgICBpZiAoIWlzVW5kZWZpbmVkKHRoaXNbbmFtZV0pICYmIGlzVHJ1ZSh0aGlzLmhhcyhPTl9DSEFJTl9VUF9ET1dOX0tFWSkpKSB7XG4gICAgICB0aGlzLmVuZCgpXG4gICAgICByZXR1cm4gdGhpcy5nZXQoT05fQ0hBSU5fVVBfRE9XTl9LRVkpKClbbmFtZV0ob25DYWxsKVxuICAgIH1cblxuICAgIC8vIEBUT0RPIG5lZWQgdG8gc3ByZWFkIGFzIG5lZWRlZFxuICAgIHRoaXNbbmFtZV0gPSBhcmdzID0+IHtcbiAgICAgIC8vIEBAZGVidWdnZXJcbiAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBkZXZzICovXG4gICAgICBpZiAoRU5WX0RFQlVHKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgIGBjYWxsZWQgJHtuYW1lfSB3aXRoOmAsXG4gICAgICAgICAgYXJncyxcbiAgICAgICAgICBgY2FsbHMgbGVuZ3RoIGlzIG5vdzpgLFxuICAgICAgICAgIHRoaXMuX2NhbGxzLnNpemVcbiAgICAgICAgKVxuICAgICAgfVxuICAgICAgaWYgKGlzVW5kZWZpbmVkKG9uQ2FsbCkpIHRoaXMuZGF0YVtuYW1lXSA9IGFyZ3NcbiAgICAgIGVsc2Ugb25DYWxsKGFyZ3MpXG5cbiAgICAgIHRoaXMuX2NhbGxzLmFkZChuYW1lKVxuXG4gICAgICAvLyBha2EgbWFnaWNSZXR1cm5cbiAgICAgIHJldHVybiB0aGlzLl9jYWxscy5zaXplID09PSB0aGlzLmdldCgnbGVuJykgPyB0aGlzLmVuZCgpIDogdGhpc1xuICAgIH1cbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjIGFjY2VzcyBkYXRhIGJlaW5nIGJ1aWx0IHdoZW4gc3RlcHBpbmcgdGhyb3VnaCBhIGZhY3RvcnlcbiAgICogQHNpbmNlIDIuMC4wXG4gICAqXG4gICAqIEBwYXJhbSAge1ByaW1pdGl2ZX0gW3Byb3A9dW5kZWZpbmVkXSBrZXkgb2YgdGhlIGRhdGEsIG9yIHJldHVybnMgYWxsIGRhdGFcbiAgICogQHJldHVybiB7YW55fSB0aGlzLmRhdGFcbiAgICpcbiAgICogQG1lbWJlck9mIEZhY3RvcnlDaGFpblxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAgICAuZGF0YVsncHJvcCddID0gJ2VoJ1xuICAgKiAgICAuZ2V0RGF0YSgncHJvcCcpXG4gICAqICAgIC8vPT4gJ2VoJ1xuICAgKiAgICAuZ2V0RGF0YSgpXG4gICAqICAgIC8vPT4ge3Byb3A6ICdlaCd9XG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqICAgIGNvbnN0IHBlcnNvbiA9IG5ldyBGYWN0b3J5Q2hhaW4odGhpcylcbiAgICogICAgY29uc3QgYWdlID0gcGVyc29uLnByb3BzKFsnbmFtZScsICdhZ2UnXSkuYWdlKDEwKS5nZXREYXRhKCdhZ2UnKVxuICAgKiAgICBleHBlY3QoYWdlKS50b0JlKDEwKVxuICAgKlxuICAgKi9cbiAgZ2V0RGF0YShwcm9wKSB7XG4gICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQ6IHNvdXJjZW1hcHMgdHJpZ2dlciBpc3RhbmJ1bCBoZXJlIGluY29ycmVjdGx5ICovXG4gICAgcmV0dXJuIGlzVW5kZWZpbmVkKHByb3ApID8gdGhpcy5kYXRhIDogdGhpcy5kYXRhW3Byb3BdXG4gIH1cblxuICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dDogc291cmNlbWFwcyB0cmlnZ2VyIGlzdGFuYnVsIGhlcmUgaW5jb3JyZWN0bHkgKi9cbiAgLyoqXG4gICAqIEBkZXNjIGNyZWF0ZXMvYWRkIHRoZSBgLmVuZGAgbWV0aG9kLCB3aGljaCBjaGVja3MgaG93IG1hbnkgbWV0aG9kcyBoYXZlIGJlZW4gY2FsbGVkLCBhbmQgZGVjaWRlcyB3aGV0aGVyIHRvIHJldHVybiBwYXJlbnQgb3Igbm90XG4gICAqICAgICAgIEBtb2RpZmllcyB0aGlzLmVuZFxuICAgKlxuICAgKiBAc2luY2UgMi4wLjBcbiAgICpcbiAgICogQHBhcmFtICB7T2JqZWN0fSBbb2JqPXt9XSBvcHRpb25hIG9iamVjdCB0byB1c2UgZm9yIGNyZWF0aW5nIC5lbmRcbiAgICogQHJldHVybiB7RmFjdG9yeUNoYWlufSBAY2hhaW5hYmxlXG4gICAqXG4gICAqIEBtZW1iZXJPZiBGYWN0b3J5Q2hhaW5cbiAgICovXG4gIGZhY3Rvcnkob2JqKSB7XG4gICAgdGhpcy5lbmQgPSBhcmcgPT4ge1xuICAgICAgLy8gQEBkZWJ1Z2dlclxuICAgICAgbGV0IGVuZGVkXG5cbiAgICAgIGlmIChvYmogJiYgIWlzVW5kZWZpbmVkKG9iai5lbmQpKSBlbmRlZCA9IG9iai5lbmRcbiAgICAgIGVsc2UgaWYgKHRoaXMuaGFzKE9OX0RPTkVfS0VZKSkgZW5kZWQgPSB0aGlzLmdldChPTl9ET05FX0tFWSlcblxuICAgICAgaWYgKGVuZGVkKSBlbmRlZCA9IGVuZGVkLmNhbGwodGhpcywgdGhpcy5kYXRhLCB0aGlzLnBhcmVudCwgdGhpcywgYXJnKVxuXG4gICAgICBpZiAoZW5kZWQgJiYgZW5kZWQgIT09IHRoaXMpIHJldHVybiBlbmRlZFxuICAgICAgZWxzZSByZXR1cm4gdGhpcy5wYXJlbnRcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpc1xuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gRmFjdG9yeUNoYWluXG4iXSwibmFtZXMiOlsiY29uc3QiLCJzdXBlciIsInRoaXMiLCJhcmd1bWVudHMiLCJsZXQiXSwibWFwcGluZ3MiOiJBQUFBQSxHQUFLLENBQUMsU0FBUyxHQUFHLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztBQUM3Q0EsR0FBSyxDQUFDLFVBQVUsR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDO0FBQzFDQSxHQUFLLENBQUMsV0FBVyxHQUFHLE9BQU8sQ0FBQyxxQkFBcUIsQ0FBQztBQUNsREEsR0FBSyxDQUFDLE1BQU0sR0FBRyxPQUFPLENBQUMsZ0JBQWdCLENBQUM7O0FBRXhDQSxHQUFLLENBQUMsb0JBQW9CLEdBQUcsZUFBZTtBQUM1Q0EsR0FBSyxDQUFDLFdBQVcsR0FBRyxRQUFROzs7Ozs7Ozs7Ozs7Ozs7O0FBZ0I1QixJQUFNLFlBQVksR0FBbUI7RUFBQyxBQUNwQyxxQkFBVyxDQUFDLE1BQU0sRUFBRTtJQUNsQkMsVUFBSyxLQUFBLENBQUMsTUFBQSxNQUFNLENBQUM7O0lBRWIsSUFBSSxDQUFDLElBQUksR0FBRyxFQUFFO0lBQ2QsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBRTs7SUFFdkIsSUFBSSxDQUFDLE9BQU8sRUFBRTtPQUNYLE1BQU0sQ0FBQyxDQUFDLFVBQVUsRUFBRSxVQUFVLEVBQUUsb0JBQW9CLEVBQUUsV0FBVyxDQUFDLENBQUM7T0FDbkUsR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7R0FDakI7Ozs7b0RBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0VBK0NELHVCQUFBLFlBQVkseUJBQUEsQ0FBQyxPQUFPLEVBQUUsQ0FBQzs7O0FBQUE7SUFDckIsT0FBTyxDQUFDLE9BQU8sQ0FBQyxVQUFBLENBQUMsQ0FBQSxDQUFDLEFBQUc7TUFDbkJDLE1BQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxTQUFBLEdBQUcsQUFBRzs7UUFFZEEsTUFBSSxDQUFDLEdBQUcsRUFBRTtR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