jiskattema/spot

View on GitHub
dist/js/npm.ampersand-state.chunk.d87280151d6296d77d24.js

Summary

Maintainability
A
0 mins
Test Coverage

FIXME found
Open

(window.webpackJsonp=window.webpackJsonp||[]).push([["npm.ampersand-state"],{ef45:function(module,exports,__webpack_require__){"use strict";eval("\n/*$AMPERSAND_VERSION*/\nvar uniqueId = __webpack_require__(/*! lodash/uniqueId */ \"6d0d\");\nvar assign = __webpack_require__(/*! lodash/assign */ \"5ad5\");\nvar cloneObj = function(obj) { return assign({}, obj); };\nvar omit = __webpack_require__(/*! lodash/omit */ \"4633\");\nvar escape = __webpack_require__(/*! lodash/escape */ \"740c\");\nvar forOwn = __webpack_require__(/*! lodash/forOwn */ \"436f\");\nvar includes = __webpack_require__(/*! lodash/includes */ \"e2c7\");\nvar isString = __webpack_require__(/*! lodash/isString */ \"5fa3\");\nvar isObject = __webpack_require__(/*! lodash/isObject */ \"d3a8\");\nvar isDate = __webpack_require__(/*! lodash/isDate */ \"7f93\");\nvar isFunction = __webpack_require__(/*! lodash/isFunction */ \"f3b0\");\nvar _isEqual = __webpack_require__(/*! lodash/isEqual */ \"f8a3\"); // to avoid shadowing\nvar has = __webpack_require__(/*! lodash/has */ \"b055\");\nvar result = __webpack_require__(/*! lodash/result */ \"80c9\");\nvar union = __webpack_require__(/*! lodash/union */ \"c80f\");\nvar Events = __webpack_require__(/*! ampersand-events */ \"13c2\");\nvar KeyTree = __webpack_require__(/*! key-tree-store */ \"8849\");\nvar arrayNext = __webpack_require__(/*! array-next */ \"d1bb\");\nvar changeRE = /^change:/;\nvar noop = function () {};\n\nfunction Base(attrs, options) {\n    options || (options = {});\n    this.cid || (this.cid = uniqueId('state'));\n    this._events = {};\n    this._values = {};\n    this._eventBubblingHandlerCache = {};\n    this._definition = Object.create(this._definition);\n    if (options.parse) attrs = this.parse(attrs, options);\n    this.parent = options.parent;\n    this.collection = options.collection;\n    this._keyTree = new KeyTree();\n    this._initCollections();\n    this._initChildren();\n    this._cache = {};\n    this._previousAttributes = {};\n    if (attrs) this.set(attrs, assign({silent: true, initial: true}, options));\n    this._changed = {};\n    if (this._derived) this._initDerived();\n    if (options.init !== false) this.initialize.apply(this, arguments);\n}\n\nassign(Base.prototype, Events, {\n    // can be allow, ignore, reject\n    extraProperties: 'ignore',\n\n    idAttribute: 'id',\n\n    namespaceAttribute: 'namespace',\n\n    typeAttribute: 'modelType',\n\n    // Stubbed out to be overwritten\n    initialize: function () {\n        return this;\n    },\n\n    // Get ID of model per configuration.\n    // Should *always* be how ID is determined by other code.\n    getId: function () {\n        return this[this.idAttribute];\n    },\n\n    // Get namespace of model per configuration.\n    // Should *always* be how namespace is determined by other code.\n    getNamespace: function () {\n        return this[this.namespaceAttribute];\n    },\n\n    // Get type of model per configuration.\n    // Should *always* be how type is determined by other code.\n    getType: function () {\n        return this[this.typeAttribute];\n    },\n\n    // A model is new if it has never been saved to the server, and lacks an id.\n    isNew: function () {\n        return this.getId() == null;\n    },\n\n    // get HTML-escaped value of attribute\n    escape: function (attr) {\n        return escape(this.get(attr));\n    },\n\n    // Check if the model is currently in a valid state.\n    isValid: function (options) {\n        return this._validate({}, assign(options || {}, { validate: true }));\n    },\n\n    // Parse can be used remap/restructure/rename incoming properties\n    // before they are applied to attributes.\n    parse: function (resp, options) {\n        //jshint unused:false\n        return resp;\n    },\n\n    // Serialize is the inverse of `parse` it lets you massage data\n    // on the way out. Before, sending to server, for example.\n    serialize: function (options) {\n        var attrOpts = assign({props: true}, options);\n        var res = this.getAttributes(attrOpts, true);\n        \n        var setFromSerializedValue = function (value, key) {\n\t        res[key] = this[key].serialize();\n        }.bind(this);\n        \n        forOwn(this._children, setFromSerializedValue);\n        forOwn(this._collections, setFromSerializedValue);\n        return res;\n    },\n\n    // Main set method used by generated setters/getters and can\n    // be used directly if you need to pass options or set multiple\n    // properties at once.\n    set: function (key, value, options) {\n        var self = this;\n        var extraProperties = this.extraProperties;\n        var wasChanging, changeEvents, newType, newVal, def, cast, err, attr,\n            attrs, dataType, silent, unset, currentVal, initial, hasChanged, isEqual, onChange;\n\n        // Handle both `\"key\", value` and `{key: value}` -style arguments.\n        if (isObject(key) || key === null) {\n            attrs = key;\n            options = value;\n        } else {\n            attrs = {};\n            attrs[key] = value;\n        }\n\n        options = options || {};\n\n        if (!this._validate(attrs, options)) return false;\n\n        // Extract attributes and options.\n        unset = options.unset;\n        silent = options.silent;\n        initial = options.initial;\n\n        // Initialize change tracking.\n        wasChanging = this._changing;\n        this._changing = true;\n        changeEvents = [];\n\n        // if not already changing, store previous\n        if (initial) {\n            this._previousAttributes = {};\n        } else if (!wasChanging) {\n            this._previousAttributes = this.attributes;\n            this._changed = {};\n        }\n\n        // For each `set` attribute...\n        for (var i = 0, keys = Object.keys(attrs), len = keys.length; i < len; i++) {\n            attr = keys[i];\n            newVal = attrs[attr];\n            newType = typeof newVal;\n            currentVal = this._values[attr];\n            def = this._definition[attr];\n\n            if (!def) {\n                // if this is a child model or collection\n                if (this._children[attr] || this._collections[attr]) {\n                    if (!isObject(newVal)) {\n                        newVal = {};\n                    }\n\n                    this[attr].set(newVal, options);\n                    continue;\n                } else if (extraProperties === 'ignore') {\n                    continue;\n                } else if (extraProperties === 'reject') {\n                    throw new TypeError('No \"' + attr + '\" property defined on ' + (this.type || 'this') + ' model and extraProperties not set to \"ignore\" or \"allow\"');\n                } else if (extraProperties === 'allow') {\n                    def = this._createPropertyDefinition(attr, 'any');\n                } else if (extraProperties) {\n                    throw new TypeError('Invalid value for extraProperties: \"' + extraProperties + '\"');\n                }\n            }\n\n            isEqual = this._getCompareForType(def.type);\n            onChange = this._getOnChangeForType(def.type);\n            dataType = this._dataTypes[def.type];\n\n            // check type if we have one\n            if (dataType && dataType.set) {\n                cast = dataType.set(newVal);\n                newVal = cast.val;\n                newType = cast.type;\n            }\n\n            // If we've defined a test, run it\n            if (def.test) {\n                err = def.test.call(this, newVal, newType);\n                if (err) {\n                    throw new TypeError('Property \\'' + attr + '\\' failed validation with error: ' + err);\n                }\n            }\n\n            // If we are required but undefined, throw error.\n            // If we are null and are not allowing null, throw error\n            // If we have a defined type and the new type doesn't match, and we are not null, throw error.\n            // If we require specific value and new one is not one of them, throw error (unless it has default value or we're unsetting it with undefined).\n\n            if (newVal === undefined && def.required) {\n                throw new TypeError('Required property \\'' + attr + '\\' must be of type ' + def.type + '. Tried to set ' + newVal);\n            }\n            if (newVal === null && def.required && !def.allowNull) {\n                throw new TypeError('Property \\'' + attr + '\\' must be of type ' + def.type + ' (cannot be null). Tried to set ' + newVal);\n            }\n            if ((def.type && def.type !== 'any' && def.type !== newType) && newVal !== null && newVal !== undefined) {\n                throw new TypeError('Property \\'' + attr + '\\' must be of type ' + def.type + '. Tried to set ' + newVal);\n            }\n            if (def.values && !includes(def.values, newVal)) {\n                var defaultValue = result(def, 'default');\n                if (unset && defaultValue !== undefined) {\n                    newVal = defaultValue;\n                } else if (!unset || (unset && newVal !== undefined)) {\n                    throw new TypeError('Property \\'' + attr + '\\' must be one of values: ' + def.values.join(', ') + '. Tried to set ' + newVal);\n                }\n            }\n\n            // We know this has 'changed' if it's the initial set, so skip a potentially expensive isEqual check.\n            hasChanged = initial || !isEqual(currentVal, newVal, attr);\n\n            // enforce `setOnce` for properties if set\n            if (def.setOnce && currentVal !== undefined && hasChanged) {\n                throw new TypeError('Property \\'' + attr + '\\' can only be set once.');\n            }\n\n            // set/unset attributes.\n            // If this is not the initial set, keep track of changed attributes\n            // and push to changeEvents array so we can fire events.\n            if (hasChanged) {\n\n                // This fires no matter what, even on initial set.\n                onChange(newVal, currentVal, attr);\n\n                // If this is a change (not an initial set), mark the change.\n                // Note it's impossible to unset on the initial set (it will already be unset),\n                // so we only include that logic here.\n                if (!initial) {\n                    this._changed[attr] = newVal;\n                    this._previousAttributes[attr] = currentVal;\n                    if (unset) {\n                        // FIXME delete is very slow. Can we get away with setting to undefined?\n                        delete this._values[attr];\n                    }\n                    if (!silent) {\n                        changeEvents.push({prev: currentVal, val: newVal, key: attr});\n                    }\n                }\n                if (!unset) {\n                    this._values[attr] = newVal;\n                }\n            } else {\n                // Not changed\n                // FIXME delete is very slow. Can we get away with setting to undefined?\n                delete this._changed[attr];\n            }\n        }\n\n        // Fire events. This array is not populated if we are told to be silent.\n        if (changeEvents.length) this._pending = true;\n        changeEvents.forEach(function (change) {\n            self.trigger('change:' + change.key, self, change.val, options);\n        });\n\n        // You might be wondering why there's a `while` loop here. Changes can\n        // be recursively nested within `\"change\"` events.\n        if (wasChanging) return this;\n        while (this._pending) {\n            this._pending = false;\n            this.trigger('change', this, options);\n        }\n        this._pending = false;\n        this._changing = false;\n        return this;\n    },\n\n    get: function (attr) {\n        return this[attr];\n    },\n\n    // Toggle boolean properties or properties that have a `values`\n    // array in its definition.\n    toggle: function (property) {\n        var def = this._definition[property];\n        if (def.type === 'boolean') {\n            // if it's a bool, just flip it\n            this[property] = !this[property];\n        } else if (def && def.values) {\n            // If it's a property with an array of values\n            // skip to the next one looping back if at end.\n            this[property] = arrayNext(def.values, this[property]);\n        } else {\n            throw new TypeError('Can only toggle properties that are type `boolean` or have `values` array.');\n        }\n        return this;\n    },\n\n    // Get all of the attributes of the model at the time of the previous\n    // `\"change\"` event.\n    previousAttributes: function () {\n        return cloneObj(this._previousAttributes);\n    },\n\n    // Determine if the model has changed since the last `\"change\"` event.\n    // If you specify an attribute name, determine if that attribute has changed.\n    hasChanged: function (attr) {\n        if (attr == null) return !!Object.keys(this._changed).length;\n        if (has(this._derived, attr)) {\n            return this._derived[attr].depList.some(function (dep) {\n                return this.hasChanged(dep);\n            }, this);\n        }\n        return has(this._changed, attr);\n    },\n\n    // Return an object containing all the attributes that have changed, or\n    // false if there are no changed attributes. Useful for determining what\n    // parts of a view need to be updated and/or what attributes need to be\n    // persisted to the server. Unset attributes will be set to undefined.\n    // You can also pass an attributes object to diff against the model,\n    // determining if there *would be* a change.\n    changedAttributes: function (diff) {\n        if (!diff) return this.hasChanged() ? cloneObj(this._changed) : false;\n        var val, changed = false;\n        var old = this._changing ? this._previousAttributes : this.attributes;\n        var def, isEqual;\n        for (var attr in diff) {\n            def = this._definition[attr];\n            if (!def) continue;\n            isEqual = this._getCompareForType(def.type);\n            if (isEqual(old[attr], (val = diff[attr]))) continue;\n            (changed || (changed = {}))[attr] = val;\n        }\n        return changed;\n    },\n\n    toJSON: function () {\n        return this.serialize();\n    },\n\n    unset: function (attrs, options) {\n        var self = this;\n        attrs = Array.isArray(attrs) ? attrs : [attrs];\n        attrs.forEach(function (key) {\n            var def = self._definition[key];\n            if (!def) return;\n            var val;\n            if (def.required) {\n                val = result(def, 'default');\n                return self.set(key, val, options);\n            } else {\n                return self.set(key, val, assign({}, options, {unset: true}));\n            }\n        });\n    },\n\n    clear: function (options) {\n        var self = this;\n        Object.keys(this.attributes).forEach(function (key) {\n            self.unset(key, options);\n        });\n        return this;\n    },\n\n    previous: function (attr) {\n        if (attr == null || !Object.keys(this._previousAttributes).length) return null;\n        return this._previousAttributes[attr];\n    },\n\n    // Get default values for a certain type\n    _getDefaultForType: function (type) {\n        var dataType = this._dataTypes[type];\n        return dataType && dataType['default'];\n    },\n\n    // Determine which comparison algorithm to use for comparing a property\n    _getCompareForType: function (type) {\n        var dataType = this._dataTypes[type];\n        if (dataType && dataType.compare) return dataType.compare.bind(this);\n        return _isEqual; // if no compare function is defined, use _.isEqual\n    },\n\n    _getOnChangeForType : function(type){\n        var dataType = this._dataTypes[type];\n        if (dataType && dataType.onChange) return dataType.onChange.bind(this);\n        return noop;\n    },\n\n    // Run validation against the next complete set of model attributes,\n    // returning `true` if all is well. Otherwise, fire an `\"invalid\"` event.\n    _validate: function (attrs, options) {\n        if (!options.validate || !this.validate) return true;\n        attrs = assign({}, this.attributes, attrs);\n        var error = this.validationError = this.validate(attrs, options) || null;\n        if (!error) return true;\n        this.trigger('invalid', this, error, assign(options || {}, {validationError: error}));\n        return false;\n    },\n\n    _createPropertyDefinition: function (name, desc, isSession) {\n        return createPropertyDefinition(this, name, desc, isSession);\n    },\n\n    // just makes friendlier errors when trying to define a new model\n    // only used when setting up original property definitions\n    _ensureValidType: function (type) {\n        return includes(['string', 'number', 'boolean', 'array', 'object', 'date', 'state', 'any']\n            .concat(Object.keys(this._dataTypes)), type) ? type : undefined;\n    },\n\n    getAttributes: function (options, raw) {\n        options = assign({\n            session: false,\n            props: false,\n            derived: false\n        }, options || {});\n        var res = {};\n        var val, def;\n        for (var item in this._definition) {\n            def = this._definition[item];\n            if ((options.session && def.session) || (options.props && !def.session)) {\n                val = raw ? this._values[item] : this[item];\n                if (raw && val && isFunction(val.serialize)) val = val.serialize();\n                if (typeof val === 'undefined') val = result(def, 'default');\n                if (typeof val !== 'undefined') res[item] = val;\n            }\n        }\n        if (options.derived) {\n            for (var derivedItem in this._derived) res[derivedItem] = this[derivedItem];\n        }\n        return res;\n    },\n\n    _initDerived: function () {\n        var self = this;\n\n        forOwn(this._derived, function (value, name) {\n            var def = self._derived[name];\n            def.deps = def.depList;\n\n            var update = function () {\n                var newVal = def.fn.call(self);\n\n                if (self._cache[name] !== newVal || !def.cache) {\n                    if (def.cache) {\n                        self._previousAttributes[name] = self._cache[name];\n                    }\n                    self._cache[name] = newVal;\n                    self.trigger('change:' + name, self, self._cache[name]);\n                }\n            };\n\n            def.deps.forEach(function (propString) {\n                self._keyTree.add(propString, update);\n            });\n        });\n\n        this.on('all', function (eventName) {\n            if (changeRE.test(eventName)) {\n                self._keyTree.get(eventName.split(':')[1]).forEach(function (fn) {\n                    fn();\n                });\n            }\n        }, this);\n    },\n\n    _getDerivedProperty: function (name, flushCache) {\n        // is this a derived property that is cached\n        if (this._derived[name].cache) {\n            //set if this is the first time, or flushCache is set\n            if (flushCache || !this._cache.hasOwnProperty(name)) {\n                this._cache[name] = this._derived[name].fn.apply(this);\n            }\n            return this._cache[name];\n        } else {\n            return this._derived[name].fn.apply(this);\n        }\n    },\n\n    _initCollections: function () {\n        var coll;\n        if (!this._collections) return;\n        for (coll in this._collections) {\n            this._safeSet(coll, new this._collections[coll](null, {parent: this}));\n        }\n    },\n\n    _initChildren: function () {\n        var child;\n        if (!this._children) return;\n        for (child in this._children) {\n            this._safeSet(child, new this._children[child]({}, {parent: this}));\n            this.listenTo(this[child], 'all', this._getCachedEventBubblingHandler(child));\n        }\n    },\n\n    // Returns a bound handler for doing event bubbling while\n    // adding a name to the change string.\n    _getCachedEventBubblingHandler: function (propertyName) {\n        if (!this._eventBubblingHandlerCache[propertyName]) {\n            this._eventBubblingHandlerCache[propertyName] = function (name, model, newValue) {\n                if (changeRE.test(name)) {\n                    this.trigger('change:' + propertyName + '.' + name.split(':')[1], model, newValue);\n                } else if (name === 'change') {\n                    this.trigger('change', this);\n                }\n            }.bind(this);\n        }\n        return this._eventBubblingHandlerCache[propertyName];\n    },\n\n    // Check that all required attributes are present\n    _verifyRequired: function () {\n        var attrs = this.attributes; // should include session\n        for (var def in this._definition) {\n            if (this._definition[def].required && typeof attrs[def] === 'undefined') {\n                return false;\n            }\n        }\n        return true;\n    },\n\n    // expose safeSet method\n    _safeSet: function safeSet(property, value) {\n        if (property in this) {\n            throw new Error('Encountered namespace collision while setting instance property `' + property + '`');\n        }\n        this[property] = value;\n        return this;\n    }\n});\n\n// getter for attributes\nObject.defineProperties(Base.prototype, {\n    attributes: {\n        get: function () {\n            return this.getAttributes({props: true, session: true});\n        }\n    },\n    all: {\n        get: function () {\n            return this.getAttributes({\n                session: true,\n                props: true,\n                derived: true\n            });\n        }\n    },\n    isState: {\n        get: function () { return true; },\n        set: function () { }\n    }\n});\n\n// helper for creating/storing property definitions and creating\n// appropriate getters/setters\nfunction createPropertyDefinition(object, name, desc, isSession) {\n    var def = object._definition[name] = {};\n    var type, descArray;\n\n    if (isString(desc)) {\n        // grab our type if all we've got is a string\n        type = object._ensureValidType(desc);\n        if (type) def.type = type;\n    } else {\n        //Transform array of ['type', required, default] to object form\n        if (Array.isArray(desc)) {\n            descArray = desc;\n            desc = {\n                type: descArray[0],\n                required: descArray[1],\n                'default': descArray[2]\n            };\n        }\n\n        type = object._ensureValidType(desc.type);\n        if (type) def.type = type;\n\n        if (desc.required) def.required = true;\n\n        if (desc['default'] && typeof desc['default'] === 'object') {\n            throw new TypeError('The default value for ' + name + ' cannot be an object/array, must be a value or a function which returns a value/object/array');\n        }\n\n        def['default'] = desc['default'];\n\n        def.allowNull = desc.allowNull ? desc.allowNull : false;\n        if (desc.setOnce) def.setOnce = true;\n        if (def.required && def['default'] === undefined && !def.setOnce) def['default'] = object._getDefaultForType(type);\n        def.test = desc.test;\n        def.values = desc.values;\n    }\n    if (isSession) def.session = true;\n\n    if (!type) {\n        type = isString(desc) ? desc : desc.type;\n        // TODO: start throwing a TypeError in future major versions instead of warning\n        console.warn('Invalid data type of `' + type + '` for `' + name + '` property. Use one of the default types or define your own');\n    }\n\n    // define a getter/setter on the prototype\n    // but they get/set on the instance\n    Object.defineProperty(object, name, {\n        set: function (val) {\n            this.set(name, val);\n        },\n        get: function () {\n            if (!this._values) {\n                throw Error('You may be trying to `extend` a state object with \"' + name + '\" which has been defined in `props` on the object being extended');\n            }\n            var value = this._values[name];\n            var typeDef = this._dataTypes[def.type];\n            if (typeof value !== 'undefined') {\n                if (typeDef && typeDef.get) {\n                    value = typeDef.get(value);\n                }\n                return value;\n            }\n            var defaultValue = result(def, 'default');\n            this._values[name] = defaultValue;\n            // If we've set a defaultValue, fire a change handler effectively marking\n            // its change from undefined to the default value.\n            if (typeof defaultValue !== 'undefined') {\n                var onChange = this._getOnChangeForType(def.type);\n                onChange(defaultValue, value, name);\n            }\n            return defaultValue;\n        }\n    });\n\n    return def;\n}\n\n// helper for creating derived property definitions\nfunction createDerivedProperty(modelProto, name, definition) {\n    var def = modelProto._derived[name] = {\n        fn: isFunction(definition) ? definition : definition.fn,\n        cache: (definition.cache !== false),\n        depList: definition.deps || []\n    };\n\n    // add to our shared dependency list\n    def.depList.forEach(function (dep) {\n        modelProto._deps[dep] = union(modelProto._deps[dep] || [], [name]);\n    });\n\n    // defined a top-level getter for derived names\n    Object.defineProperty(modelProto, name, {\n        get: function () {\n            return this._getDerivedProperty(name);\n        },\n        set: function () {\n            throw new TypeError(\"`\" + name + \"` is a derived property, it can't be set directly.\");\n        }\n    });\n}\n\nvar dataTypes = {\n    string: {\n        'default': function () {\n            return '';\n        }\n    },\n    date: {\n        set: function (newVal) {\n            var newType;\n            if (newVal == null) {\n                newType = typeof null;\n            } else if (!isDate(newVal)) {\n                var err = null;\n                var dateVal = new Date(newVal).valueOf();\n                if (isNaN(dateVal)) {\n                    // If the newVal cant be parsed, then try parseInt first\n                    dateVal = new Date(parseInt(newVal, 10)).valueOf();\n                    if (isNaN(dateVal)) err = true;\n                }\n                newVal = dateVal;\n                newType = 'date';\n                if (err) {\n                    newType = typeof newVal;\n                }\n            } else {\n                newType = 'date';\n                newVal = newVal.valueOf();\n            }\n\n            return {\n                val: newVal,\n                type: newType\n            };\n        },\n        get: function (val) {\n            if (val == null) { return val; }\n            return new Date(val);\n        },\n        'default': function () {\n            return new Date();\n        }\n    },\n    array: {\n        set: function (newVal) {\n            return {\n                val: newVal,\n                type: Array.isArray(newVal) ? 'array' : typeof newVal\n            };\n        },\n        'default': function () {\n            return [];\n        }\n    },\n    object: {\n        set: function (newVal) {\n            var newType = typeof newVal;\n            // we have to have a way of supporting \"missing\" objects.\n            // Null is an object, but setting a value to undefined\n            // should work too, IMO. We just override it, in that case.\n            if (newType !== 'object' && newVal === undefined) {\n                newVal = null;\n                newType = 'object';\n            }\n            return {\n                val: newVal,\n                type: newType\n            };\n        },\n        'default': function () {\n            return {};\n        }\n    },\n    // the `state` data type is a bit special in that setting it should\n    // also bubble events\n    state: {\n        set: function (newVal) {\n            var isInstance = newVal instanceof Base || (newVal && newVal.isState);\n            if (isInstance) {\n                return {\n                    val: newVal,\n                    type: 'state'\n                };\n            } else {\n                return {\n                    val: newVal,\n                    type: typeof newVal\n                };\n            }\n        },\n        compare: function (currentVal, newVal) {\n            return currentVal === newVal;\n        },\n\n        onChange : function(newVal, previousVal, attributeName){\n            // if this has changed we want to also handle\n            // event propagation\n            if (previousVal) {\n                this.stopListening(previousVal, 'all', this._getCachedEventBubblingHandler(attributeName));\n            }\n\n            if (newVal != null) {\n                this.listenTo(newVal, 'all', this._getCachedEventBubblingHandler(attributeName));\n            }\n        }\n    }\n};\n\n// the extend method used to extend prototypes, maintain inheritance chains for instanceof\n// and allow for additions to the model definitions.\nfunction extend(protoProps) {\n    /*jshint validthis:true*/\n    var parent = this;\n    var child;\n\n    // The constructor function for the new subclass is either defined by you\n    // (the \"constructor\" property in your `extend` definition), or defaulted\n    // by us to simply call the parent's constructor.\n    if (protoProps && protoProps.hasOwnProperty('constructor')) {\n        child = protoProps.constructor;\n    } else {\n        child = function () {\n            return parent.apply(this, arguments);\n        };\n    }\n\n    // Add static properties to the constructor function from parent\n    assign(child, parent);\n\n    // Set the prototype chain to inherit from `parent`, without calling\n    // `parent`'s constructor function.\n    var Surrogate = function () { this.constructor = child; };\n    Surrogate.prototype = parent.prototype;\n    child.prototype = new Surrogate();\n\n    // set prototype level objects\n    child.prototype._derived =  assign({}, parent.prototype._derived);\n    child.prototype._deps = assign({}, parent.prototype._deps);\n    child.prototype._definition = assign({}, parent.prototype._definition);\n    child.prototype._collections = assign({}, parent.prototype._collections);\n    child.prototype._children = assign({}, parent.prototype._children);\n    child.prototype._dataTypes = assign({}, parent.prototype._dataTypes || dataTypes);\n\n    // Mix in all prototype properties to the subclass if supplied.\n    if (protoProps) {\n        var omitFromExtend = [\n            'dataTypes', 'props', 'session', 'derived', 'collections', 'children'\n        ];\n        for(var i = 0; i < arguments.length; i++) {\n            var def = arguments[i];\n            if (def.dataTypes) {\n                forOwn(def.dataTypes, function (def, name) {\n                    child.prototype._dataTypes[name] = def;\n                });\n            }\n            if (def.props) {\n                forOwn(def.props, function (def, name) {\n                    createPropertyDefinition(child.prototype, name, def);\n                });\n            }\n            if (def.session) {\n                forOwn(def.session, function (def, name) {\n                    createPropertyDefinition(child.prototype, name, def, true);\n                });\n            }\n            if (def.derived) {\n                forOwn(def.derived, function (def, name) {\n                    createDerivedProperty(child.prototype, name, def);\n                });\n            }\n            if (def.collections) {\n                forOwn(def.collections, function (constructor, name) {\n                    child.prototype._collections[name] = constructor;\n                });\n            }\n            if (def.children) {\n                forOwn(def.children, function (constructor, name) {\n                    child.prototype._children[name] = constructor;\n                });\n            }\n            assign(child.prototype, omit(def, omitFromExtend));\n        }\n    }\n\n    // Set a convenience property in case the parent's prototype is needed\n    // later.\n    child.__super__ = parent.prototype;\n\n    return child;\n}\n\nBase.extend = extend;\n\n// Our main exports\nmodule.exports = Base;\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWY0NS5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9hbXBlcnNhbmQtc3RhdGUvYW1wZXJzYW5kLXN0YXRlLmpzPzYzZDQiXSwic291cmNlc0NvbnRlbnQiOlsiJ3VzZSBzdHJpY3QnO1xuLyokQU1QRVJTQU5EX1ZFUlNJT04qL1xudmFyIHVuaXF1ZUlkID0gcmVxdWlyZSgnbG9kYXNoL3VuaXF1ZUlkJyk7XG52YXIgYXNzaWduID0gcmVxdWlyZSgnbG9kYXNoL2Fzc2lnbicpO1xudmFyIGNsb25lT2JqID0gZnVuY3Rpb24ob2JqKSB7IHJldHVybiBhc3NpZ24oe30sIG9iaik7IH07XG52YXIgb21pdCA9IHJlcXVpcmUoJ2xvZGFzaC9vbWl0Jyk7XG52YXIgZXNjYXBlID0gcmVxdWlyZSgnbG9kYXNoL2VzY2FwZScpO1xudmFyIGZvck93biA9IHJlcXVpcmUoJ2xvZGFzaC9mb3JPd24nKTtcbnZhciBpbmNsdWRlcyA9IHJlcXVpcmUoJ2xvZGFzaC9pbmNsdWRlcycpO1xudmFyIGlzU3RyaW5nID0gcmVxdWlyZSgnbG9kYXNoL2lzU3RyaW5nJyk7XG52YXIgaXNPYmplY3QgPSByZXF1aXJlKCdsb2Rhc2gvaXNPYmplY3QnKTtcbnZhciBpc0RhdGUgPSByZXF1aXJlKCdsb2Rhc2gvaXNEYXRlJyk7XG52YXIgaXNGdW5jdGlvbiA9IHJlcXVpcmUoJ2xvZGFzaC9pc0Z1bmN0aW9uJyk7XG52YXIgX2lzRXF1YWwgPSByZXF1aXJlKCdsb2Rhc2gvaXNFcXVhbCcpOyAvLyB0byBhdm9pZCBzaGFkb3dpbmdcbnZhciBoYXMgPSByZXF1aXJlKCdsb2Rhc2gvaGFzJyk7XG52YXIgcmVzdWx0ID0gcmVxdWlyZSgnbG9kYXNoL3Jlc3VsdCcpO1xudmFyIHVuaW9uID0gcmVxdWlyZSgnbG9kYXNoL3VuaW9uJyk7XG52YXIgRXZlbnRzID0gcmVxdWlyZSgnYW1wZXJzYW5kLWV2ZW50cycpO1xudmFyIEtleVRyZWUgPSByZXF1aXJlKCdrZXktdHJlZS1zdG9yZScpO1xudmFyIGFycmF5TmV4dCA9IHJlcXVpcmUoJ2FycmF5LW5leHQnKTtcbnZhciBjaGFuZ2VSRSA9IC9eY2hhbmdlOi87XG52YXIgbm9vcCA9IGZ1bmN0aW9uICgpIHt9O1xuXG5mdW5jdGlvbiBCYXNlKGF0dHJzLCBvcHRpb25zKSB7XG4gICAgb3B0aW9ucyB8fCAob3B0aW9ucyA9IHt9KTtcbiAgICB0aGlzLmNpZCB8fCAodGhpcy5jaWQgPSB1bmlxdWVJZCgnc3RhdGUnKSk7XG4gICAgdGhpcy5fZXZlbnRzID0ge307XG4gICAgdGhpcy5fdmFsdWVzID0ge307XG4gICAgdGhpcy5fZXZlbnRCdWJibGluZ0hhbmRsZXJDYWNoZSA9IHt9O1xuICAgIHRoaXMuX2RlZmluaXRpb24gPSBPYmplY3QuY3JlYXRlKHRoaXMuX2RlZmluaXRpb24pO1xuICAgIGlmIChvcHRpb25zLnBhcnNlKSBhdHRycyA9IHRoaXMucGFyc2UoYXR0cnMsIG9wdGlvbnMpO1xuICAgIHRoaXMucGFyZW50ID0gb3B0aW9ucy5wYXJlbnQ7XG4gICAgdGhpcy5jb2xsZWN0aW9uID0gb3B0aW9ucy5jb2xsZWN0aW9uO1xuICAgIHRoaXMuX2tleVRyZWUgPSBuZXcgS2V5VHJlZSgpO1xuICAgIHRoaXMuX2luaXRDb2xsZWN0aW9ucygpO1xuICAgIHRoaXMuX2luaXRDaGlsZHJlbigpO1xuICAgIHRoaXMuX2NhY2hlID0ge307XG4gICAgdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzID0ge307XG4gICAgaWYgKGF0dHJzKSB0aGlzLnNldChhdHRycywgYXNzaWduKHtzaWxlbnQ6IHRydWUsIGluaXRpYWw6IHRydWV9LCBvcHRpb25zKSk7XG4gICAgdGhpcy5fY2hhbmdlZCA9IHt9O1xuICAgIGlmICh0aGlzLl9kZXJpdmVkKSB0aGlzLl9pbml0RGVyaXZlZCgpO1xuICAgIGlmIChvcHRpb25zLmluaXQgIT09IGZhbHNlKSB0aGlzLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cblxuYXNzaWduKEJhc2UucHJvdG90eXBlLCBFdmVudHMsIHtcbiAgICAvLyBjYW4gYmUgYWxsb3csIGlnbm9yZSwgcmVqZWN0XG4gICAgZXh0cmFQcm9wZXJ0aWVzOiAnaWdub3JlJyxcblxuICAgIGlkQXR0cmlidXRlOiAnaWQnLFxuXG4gICAgbmFtZXNwYWNlQXR0cmlidXRlOiAnbmFtZXNwYWNlJyxcblxuICAgIHR5cGVBdHRyaWJ1dGU6ICdtb2RlbFR5cGUnLFxuXG4gICAgLy8gU3R1YmJlZCBvdXQgdG8gYmUgb3ZlcndyaXR0ZW5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICAvLyBHZXQgSUQgb2YgbW9kZWwgcGVyIGNvbmZpZ3VyYXRpb24uXG4gICAgLy8gU2hvdWxkICphbHdheXMqIGJlIGhvdyBJRCBpcyBkZXRlcm1pbmVkIGJ5IG90aGVyIGNvZGUuXG4gICAgZ2V0SWQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXNbdGhpcy5pZEF0dHJpYnV0ZV07XG4gICAgfSxcblxuICAgIC8vIEdldCBuYW1lc3BhY2Ugb2YgbW9kZWwgcGVyIGNvbmZpZ3VyYXRpb24uXG4gICAgLy8gU2hvdWxkICphbHdheXMqIGJlIGhvdyBuYW1lc3BhY2UgaXMgZGV0ZXJtaW5lZCBieSBvdGhlciBjb2RlLlxuICAgIGdldE5hbWVzcGFjZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpc1t0aGlzLm5hbWVzcGFjZUF0dHJpYnV0ZV07XG4gICAgfSxcblxuICAgIC8vIEdldCB0eXBlIG9mIG1vZGVsIHBlciBjb25maWd1cmF0aW9uLlxuICAgIC8vIFNob3VsZCAqYWx3YXlzKiBiZSBob3cgdHlwZSBpcyBkZXRlcm1pbmVkIGJ5IG90aGVyIGNvZGUuXG4gICAgZ2V0VHlwZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpc1t0aGlzLnR5cGVBdHRyaWJ1dGVdO1xuICAgIH0sXG5cbiAgICAvLyBBIG1vZGVsIGlzIG5ldyBpZiBpdCBoYXMgbmV2ZXIgYmVlbiBzYXZlZCB0byB0aGUgc2VydmVyLCBhbmQgbGFja3MgYW4gaWQuXG4gICAgaXNOZXc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0SWQoKSA9PSBudWxsO1xuICAgIH0sXG5cbiAgICAvLyBnZXQgSFRNTC1lc2NhcGVkIHZhbHVlIG9mIGF0dHJpYnV0ZVxuICAgIGVzY2FwZTogZnVuY3Rpb24gKGF0dHIpIHtcbiAgICAgICAgcmV0dXJuIGVzY2FwZSh0aGlzLmdldChhdHRyKSk7XG4gICAgfSxcblxuICAgIC8vIENoZWNrIGlmIHRoZSBtb2RlbCBpcyBjdXJyZW50bHkgaW4gYSB2YWxpZCBzdGF0ZS5cbiAgICBpc1ZhbGlkOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5fdmFsaWRhdGUoe30sIGFzc2lnbihvcHRpb25zIHx8IHt9LCB7IHZhbGlkYXRlOiB0cnVlIH0pKTtcbiAgICB9LFxuXG4gICAgLy8gUGFyc2UgY2FuIGJlIHVzZWQgcmVtYXAvcmVzdHJ1Y3R1cmUvcmVuYW1lIGluY29taW5nIHByb3BlcnRpZXNcbiAgICAvLyBiZWZvcmUgdGhleSBhcmUgYXBwbGllZCB0byBhdHRyaWJ1dGVzLlxuICAgIHBhcnNlOiBmdW5jdGlvbiAocmVzcCwgb3B0aW9ucykge1xuICAgICAgICAvL2pzaGludCB1bnVzZWQ6ZmFsc2VcbiAgICAgICAgcmV0dXJuIHJlc3A7XG4gICAgfSxcblxuICAgIC8vIFNlcmlhbGl6ZSBpcyB0aGUgaW52ZXJzZSBvZiBgcGFyc2VgIGl0IGxldHMgeW91IG1hc3NhZ2UgZGF0YVxuICAgIC8vIG9uIHRoZSB3YXkgb3V0LiBCZWZvcmUsIHNlbmRpbmcgdG8gc2VydmVyLCBmb3IgZXhhbXBsZS5cbiAgICBzZXJpYWxpemU6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBhdHRyT3B0cyA9IGFzc2lnbih7cHJvcHM6IHRydWV9LCBvcHRpb25zKTtcbiAgICAgICAgdmFyIHJlcyA9IHRoaXMuZ2V0QXR0cmlidXRlcyhhdHRyT3B0cywgdHJ1ZSk7XG4gICAgICAgIFxuICAgICAgICB2YXIgc2V0RnJvbVNlcmlhbGl6ZWRWYWx1ZSA9IGZ1bmN0aW9uICh2YWx1ZSwga2V5KSB7XG5cdCAgICAgICAgcmVzW2tleV0gPSB0aGlzW2tleV0uc2VyaWFsaXplKCk7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcbiAgICAgICAgXG4gICAgICAgIGZvck93bih0aGlzLl9jaGlsZHJlbiwgc2V0RnJvbVNlcmlhbGl6ZWRWYWx1ZSk7XG4gICAgICAgIGZvck93bih0aGlzLl9jb2xsZWN0aW9ucywgc2V0RnJvbVNlcmlhbGl6ZWRWYWx1ZSk7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfSxcblxuICAgIC8vIE1haW4gc2V0IG1ldGhvZCB1c2VkIGJ5IGdlbmVyYXRlZCBzZXR0ZXJzL2dldHRlcnMgYW5kIGNhblxuICAgIC8vIGJlIHVzZWQgZGlyZWN0bHkgaWYgeW91IG5lZWQgdG8gcGFzcyBvcHRpb25zIG9yIHNldCBtdWx0aXBsZVxuICAgIC8vIHByb3BlcnRpZXMgYXQgb25jZS5cbiAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgdmFyIGV4dHJhUHJvcGVydGllcyA9IHRoaXMuZXh0cmFQcm9wZXJ0aWVzO1xuICAgICAgICB2YXIgd2FzQ2hhbmdpbmcsIGNoYW5nZUV2ZW50cywgbmV3VHlwZSwgbmV3VmFsLCBkZWYsIGNhc3QsIGVyciwgYXR0cixcbiAgICAgICAgICAgIGF0dHJzLCBkYXRhVHlwZSwgc2lsZW50LCB1bnNldCwgY3VycmVudFZhbCwgaW5pdGlhbCwgaGFzQ2hhbmdlZCwgaXNFcXVhbCwgb25DaGFuZ2U7XG5cbiAgICAgICAgLy8gSGFuZGxlIGJvdGggYFwia2V5XCIsIHZhbHVlYCBhbmQgYHtrZXk6IHZhbHVlfWAgLXN0eWxlIGFyZ3VtZW50cy5cbiAgICAgICAgaWYgKGlzT2JqZWN0KGtleSkgfHwga2V5ID09PSBudWxsKSB7XG4gICAgICAgICAgICBhdHRycyA9IGtleTtcbiAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGF0dHJzID0ge307XG4gICAgICAgICAgICBhdHRyc1trZXldID0gdmFsdWU7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICBpZiAoIXRoaXMuX3ZhbGlkYXRlKGF0dHJzLCBvcHRpb25zKSkgcmV0dXJuIGZhbHNlO1xuXG4gICAgICAgIC8vIEV4dHJhY3QgYXR0cmlidXRlcyBhbmQgb3B0aW9ucy5cbiAgICAgICAgdW5zZXQgPSBvcHRpb25zLnVuc2V0O1xuICAgICAgICBzaWxlbnQgPSBvcHRpb25zLnNpbGVudDtcbiAgICAgICAgaW5pdGlhbCA9IG9wdGlvbnMuaW5pdGlhbDtcblxuICAgICAgICAvLyBJbml0aWFsaXplIGNoYW5nZSB0cmFja2luZy5cbiAgICAgICAgd2FzQ2hhbmdpbmcgPSB0aGlzLl9jaGFuZ2luZztcbiAgICAgICAgdGhpcy5fY2hhbmdpbmcgPSB0cnVlO1xuICAgICAgICBjaGFuZ2VFdmVudHMgPSBbXTtcblxuICAgICAgICAvLyBpZiBub3QgYWxyZWFkeSBjaGFuZ2luZywgc3RvcmUgcHJldmlvdXNcbiAgICAgICAgaWYgKGluaXRpYWwpIHtcbiAgICAgICAgICAgIHRoaXMuX3ByZXZpb3VzQXR0cmlidXRlcyA9IHt9O1xuICAgICAgICB9IGVsc2UgaWYgKCF3YXNDaGFuZ2luZykge1xuICAgICAgICAgICAgdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzID0gdGhpcy5hdHRyaWJ1dGVzO1xuICAgICAgICAgICAgdGhpcy5fY2hhbmdlZCA9IHt9O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRm9yIGVhY2ggYHNldGAgYXR0cmlidXRlLi4uXG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBrZXlzID0gT2JqZWN0LmtleXMoYXR0cnMpLCBsZW4gPSBrZXlzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgICAgICBhdHRyID0ga2V5c1tpXTtcbiAgICAgICAgICAgIG5ld1ZhbCA9IGF0dHJzW2F0dHJdO1xuICAgICAgICAgICAgbmV3VHlwZSA9IHR5cGVvZiBuZXdWYWw7XG4gICAgICAgICAgICBjdXJyZW50VmFsID0gdGhpcy5fdmFsdWVzW2F0dHJdO1xuICAgICAgICAgICAgZGVmID0gdGhpcy5fZGVmaW5pdGlvblthdHRyXTtcblxuICAgICAgICAgICAgaWYgKCFkZWYpIHtcbiAgICAgICAgICAgICAgICAvLyBpZiB0aGlzIGlzIGEgY2hpbGQgbW9kZWwgb3IgY29sbGVjdGlvblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLl9jaGlsZHJlblthdHRyXSB8fCB0aGlzLl9jb2xsZWN0aW9uc1thdHRyXSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWlzT2JqZWN0KG5ld1ZhbCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5ld1ZhbCA9IHt9O1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpc1thdHRyXS5zZXQobmV3VmFsLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChleHRyYVByb3BlcnRpZXMgPT09ICdpZ25vcmUnKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoZXh0cmFQcm9wZXJ0aWVzID09PSAncmVqZWN0Jykge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdObyBcIicgKyBhdHRyICsgJ1wiIHByb3BlcnR5IGRlZmluZWQgb24gJyArICh0aGlzLnR5cGUgfHwgJ3RoaXMnKSArICcgbW9kZWwgYW5kIGV4dHJhUHJvcGVydGllcyBub3Qgc2V0IHRvIFwiaWdub3JlXCIgb3IgXCJhbGxvd1wiJyk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChleHRyYVByb3BlcnRpZXMgPT09ICdhbGxvdycpIHtcbiAgICAgICAgICAgICAgICAgICAgZGVmID0gdGhpcy5fY3JlYXRlUHJvcGVydHlEZWZpbml0aW9uKGF0dHIsICdhbnknKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGV4dHJhUHJvcGVydGllcykge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdJbnZhbGlkIHZhbHVlIGZvciBleHRyYVByb3BlcnRpZXM6IFwiJyArIGV4dHJhUHJvcGVydGllcyArICdcIicpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaXNFcXVhbCA9IHRoaXMuX2dldENvbXBhcmVGb3JUeXBlKGRlZi50eXBlKTtcbiAgICAgICAgICAgIG9uQ2hhbmdlID0gdGhpcy5fZ2V0T25DaGFuZ2VGb3JUeXBlKGRlZi50eXBlKTtcbiAgICAgICAgICAgIGRhdGFUeXBlID0gdGhpcy5fZGF0YVR5cGVzW2RlZi50eXBlXTtcblxuICAgICAgICAgICAgLy8gY2hlY2sgdHlwZSBpZiB3ZSBoYXZlIG9uZVxuICAgICAgICAgICAgaWYgKGRhdGFUeXBlICYmIGRhdGFUeXBlLnNldCkge1xuICAgICAgICAgICAgICAgIGNhc3QgPSBkYXRhVHlwZS5zZXQobmV3VmFsKTtcbiAgICAgICAgICAgICAgICBuZXdWYWwgPSBjYXN0LnZhbDtcbiAgICAgICAgICAgICAgICBuZXdUeXBlID0gY2FzdC50eXBlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBJZiB3ZSd2ZSBkZWZpbmVkIGEgdGVzdCwgcnVuIGl0XG4gICAgICAgICAgICBpZiAoZGVmLnRlc3QpIHtcbiAgICAgICAgICAgICAgICBlcnIgPSBkZWYudGVzdC5jYWxsKHRoaXMsIG5ld1ZhbCwgbmV3VHlwZSk7XG4gICAgICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdQcm9wZXJ0eSBcXCcnICsgYXR0ciArICdcXCcgZmFpbGVkIHZhbGlkYXRpb24gd2l0aCBlcnJvcjogJyArIGVycik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBJZiB3ZSBhcmUgcmVxdWlyZWQgYnV0IHVuZGVmaW5lZCwgdGhyb3cgZXJyb3IuXG4gICAgICAgICAgICAvLyBJZiB3ZSBhcmUgbnVsbCBhbmQgYXJlIG5vdCBhbGxvd2luZyBudWxsLCB0aHJvdyBlcnJvclxuICAgICAgICAgICAgLy8gSWYgd2UgaGF2ZSBhIGRlZmluZWQgdHlwZSBhbmQgdGhlIG5ldyB0eXBlIGRvZXNuJ3QgbWF0Y2gsIGFuZCB3ZSBhcmUgbm90IG51bGwsIHRocm93IGVycm9yLlxuICAgICAgICAgICAgLy8gSWYgd2UgcmVxdWlyZSBzcGVjaWZpYyB2YWx1ZSBhbmQgbmV3IG9uZSBpcyBub3Qgb25lIG9mIHRoZW0sIHRocm93IGVycm9yICh1bmxlc3MgaXQgaGFzIGRlZmF1bHQgdmFsdWUgb3Igd2UncmUgdW5zZXR0aW5nIGl0IHdpdGggdW5kZWZpbmVkKS5cblxuICAgICAgICAgICAgaWYgKG5ld1ZhbCA9PT0gdW5kZWZpbmVkICYmIGRlZi5yZXF1aXJlZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1JlcXVpcmVkIHByb3BlcnR5IFxcJycgKyBhdHRyICsgJ1xcJyBtdXN0IGJlIG9mIHR5cGUgJyArIGRlZi50eXBlICsgJy4gVHJpZWQgdG8gc2V0ICcgKyBuZXdWYWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG5ld1ZhbCA9PT0gbnVsbCAmJiBkZWYucmVxdWlyZWQgJiYgIWRlZi5hbGxvd051bGwpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdQcm9wZXJ0eSBcXCcnICsgYXR0ciArICdcXCcgbXVzdCBiZSBvZiB0eXBlICcgKyBkZWYudHlwZSArICcgKGNhbm5vdCBiZSBudWxsKS4gVHJpZWQgdG8gc2V0ICcgKyBuZXdWYWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKChkZWYudHlwZSAmJiBkZWYudHlwZSAhPT0gJ2FueScgJiYgZGVmLnR5cGUgIT09IG5ld1R5cGUpICYmIG5ld1ZhbCAhPT0gbnVsbCAmJiBuZXdWYWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Byb3BlcnR5IFxcJycgKyBhdHRyICsgJ1xcJyBtdXN0IGJlIG9mIHR5cGUgJyArIGRlZi50eXBlICsgJy4gVHJpZWQgdG8gc2V0ICcgKyBuZXdWYWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRlZi52YWx1ZXMgJiYgIWluY2x1ZGVzKGRlZi52YWx1ZXMsIG5ld1ZhbCkpIHtcbiAgICAgICAgICAgICAgICB2YXIgZGVmYXVsdFZhbHVlID0gcmVzdWx0KGRlZiwgJ2RlZmF1bHQnKTtcbiAgICAgICAgICAgICAgICBpZiAodW5zZXQgJiYgZGVmYXVsdFZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgbmV3VmFsID0gZGVmYXVsdFZhbHVlO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoIXVuc2V0IHx8ICh1bnNldCAmJiBuZXdWYWwgIT09IHVuZGVmaW5lZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignUHJvcGVydHkgXFwnJyArIGF0dHIgKyAnXFwnIG11c3QgYmUgb25lIG9mIHZhbHVlczogJyArIGRlZi52YWx1ZXMuam9pbignLCAnKSArICcuIFRyaWVkIHRvIHNldCAnICsgbmV3VmFsKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFdlIGtub3cgdGhpcyBoYXMgJ2NoYW5nZWQnIGlmIGl0J3MgdGhlIGluaXRpYWwgc2V0LCBzbyBza2lwIGEgcG90ZW50aWFsbHkgZXhwZW5zaXZlIGlzRXF1YWwgY2hlY2suXG4gICAgICAgICAgICBoYXNDaGFuZ2VkID0gaW5pdGlhbCB8fCAhaXNFcXVhbChjdXJyZW50VmFsLCBuZXdWYWwsIGF0dHIpO1xuXG4gICAgICAgICAgICAvLyBlbmZvcmNlIGBzZXRPbmNlYCBmb3IgcHJvcGVydGllcyBpZiBzZXRcbiAgICAgICAgICAgIGlmIChkZWYuc2V0T25jZSAmJiBjdXJyZW50VmFsICE9PSB1bmRlZmluZWQgJiYgaGFzQ2hhbmdlZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Byb3BlcnR5IFxcJycgKyBhdHRyICsgJ1xcJyBjYW4gb25seSBiZSBzZXQgb25jZS4nKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gc2V0L3Vuc2V0IGF0dHJpYnV0ZXMuXG4gICAgICAgICAgICAvLyBJZiB0aGlzIGlzIG5vdCB0aGUgaW5pdGlhbCBzZXQsIGtlZXAgdHJhY2sgb2YgY2hhbmdlZCBhdHRyaWJ1dGVzXG4gICAgICAgICAgICAvLyBhbmQgcHVzaCB0byBjaGFuZ2VFdmVudHMgYXJyYXkgc28gd2UgY2FuIGZpcmUgZXZlbnRzLlxuICAgICAgICAgICAgaWYgKGhhc0NoYW5nZWQpIHtcblxuICAgICAgICAgICAgICAgIC8vIFRoaXMgZmlyZXMgbm8gbWF0dGVyIHdoYXQsIGV2ZW4gb24gaW5pdGlhbCBzZXQuXG4gICAgICAgICAgICAgICAgb25DaGFuZ2UobmV3VmFsLCBjdXJyZW50VmFsLCBhdHRyKTtcblxuICAgICAgICAgICAgICAgIC8vIElmIHRoaXMgaXMgYSBjaGFuZ2UgKG5vdCBhbiBpbml0aWFsIHNldCksIG1hcmsgdGhlIGNoYW5nZS5cbiAgICAgICAgICAgICAgICAvLyBOb3RlIGl0J3MgaW1wb3NzaWJsZSB0byB1bnNldCBvbiB0aGUgaW5pdGlhbCBzZXQgKGl0IHdpbGwgYWxyZWFkeSBiZSB1bnNldCksXG4gICAgICAgICAgICAgICAgLy8gc28gd2Ugb25seSBpbmNsdWRlIHRoYXQgbG9naWMgaGVyZS5cbiAgICAgICAgICAgICAgICBpZiAoIWluaXRpYWwpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fY2hhbmdlZFthdHRyXSA9IG5ld1ZhbDtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzW2F0dHJdID0gY3VycmVudFZhbDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHVuc2V0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBGSVhNRSBkZWxldGUgaXMgdmVyeSBzbG93LiBDYW4gd2UgZ2V0IGF3YXkgd2l0aCBzZXR0aW5nIHRvIHVuZGVmaW5lZD9cbiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLl92YWx1ZXNbYXR0cl07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFzaWxlbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNoYW5nZUV2ZW50cy5wdXNoKHtwcmV2OiBjdXJyZW50VmFsLCB2YWw6IG5ld1ZhbCwga2V5OiBhdHRyfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCF1bnNldCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl92YWx1ZXNbYXR0cl0gPSBuZXdWYWw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBOb3QgY2hhbmdlZFxuICAgICAgICAgICAgICAgIC8vIEZJWE1FIGRlbGV0ZSBpcyB2ZXJ5IHNsb3cuIENhbiB3ZSBnZXQgYXdheSB3aXRoIHNldHRpbmcgdG8gdW5kZWZpbmVkP1xuICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLl9jaGFuZ2VkW2F0dHJdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gRmlyZSBldmVudHMuIFRoaXMgYXJyYXkgaXMgbm90IHBvcHVsYXRlZCBpZiB3ZSBhcmUgdG9sZCB0byBiZSBzaWxlbnQuXG4gICAgICAgIGlmIChjaGFuZ2VFdmVudHMubGVuZ3RoKSB0aGlzLl9wZW5kaW5nID0gdHJ1ZTtcbiAgICAgICAgY2hhbmdlRXZlbnRzLmZvckVhY2goZnVuY3Rpb24gKGNoYW5nZSkge1xuICAgICAgICAgICAgc2VsZi50cmlnZ2VyKCdjaGFuZ2U6JyArIGNoYW5nZS5rZXksIHNlbGYsIGNoYW5nZS52YWwsIG9wdGlvbnMpO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBZb3UgbWlnaHQgYmUgd29uZGVyaW5nIHdoeSB0aGVyZSdzIGEgYHdoaWxlYCBsb29wIGhlcmUuIENoYW5nZXMgY2FuXG4gICAgICAgIC8vIGJlIHJlY3Vyc2l2ZWx5IG5lc3RlZCB3aXRoaW4gYFwiY2hhbmdlXCJgIGV2ZW50cy5cbiAgICAgICAgaWYgKHdhc0NoYW5naW5nKSByZXR1cm4gdGhpcztcbiAgICAgICAgd2hpbGUgKHRoaXMuX3BlbmRpbmcpIHtcbiAgICAgICAgICAgIHRoaXMuX3BlbmRpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMudHJpZ2dlcignY2hhbmdlJywgdGhpcywgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fcGVuZGluZyA9IGZhbHNlO1xuICAgICAgICB0aGlzLl9jaGFuZ2luZyA9IGZhbHNlO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuXG4gICAgZ2V0OiBmdW5jdGlvbiAoYXR0cikge1xuICAgICAgICByZXR1cm4gdGhpc1thdHRyXTtcbiAgICB9LFxuXG4gICAgLy8gVG9nZ2xlIGJvb2xlYW4gcHJvcGVydGllcyBvciBwcm9wZXJ0aWVzIHRoYXQgaGF2ZSBhIGB2YWx1ZXNgXG4gICAgLy8gYXJyYXkgaW4gaXRzIGRlZmluaXRpb24uXG4gICAgdG9nZ2xlOiBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgdmFyIGRlZiA9IHRoaXMuX2RlZmluaXRpb25bcHJvcGVydHldO1xuICAgICAgICBpZiAoZGVmLnR5cGUgPT09ICdib29sZWFuJykge1xuICAgICAgICAgICAgLy8gaWYgaXQncyBhIGJvb2wsIGp1c3QgZmxpcCBpdFxuICAgICAgICAgICAgdGhpc1twcm9wZXJ0eV0gPSAhdGhpc1twcm9wZXJ0eV07XG4gICAgICAgIH0gZWxzZSBpZiAoZGVmICYmIGRlZi52YWx1ZXMpIHtcbiAgICAgICAgICAgIC8vIElmIGl0J3MgYSBwcm9wZXJ0eSB3aXRoIGFuIGFycmF5IG9mIHZhbHVlc1xuICAgICAgICAgICAgLy8gc2tpcCB0byB0aGUgbmV4dCBvbmUgbG9vcGluZyBiYWNrIGlmIGF0IGVuZC5cbiAgICAgICAgICAgIHRoaXNbcHJvcGVydHldID0gYXJyYXlOZXh0KGRlZi52YWx1ZXMsIHRoaXNbcHJvcGVydHldKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0NhbiBvbmx5IHRvZ2dsZSBwcm9wZXJ0aWVzIHRoYXQgYXJlIHR5cGUgYGJvb2xlYW5gIG9yIGhhdmUgYHZhbHVlc2AgYXJyYXkuJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIC8vIEdldCBhbGwgb2YgdGhlIGF0dHJpYnV0ZXMgb2YgdGhlIG1vZGVsIGF0IHRoZSB0aW1lIG9mIHRoZSBwcmV2aW91c1xuICAgIC8vIGBcImNoYW5nZVwiYCBldmVudC5cbiAgICBwcmV2aW91c0F0dHJpYnV0ZXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGNsb25lT2JqKHRoaXMuX3ByZXZpb3VzQXR0cmlidXRlcyk7XG4gICAgfSxcblxuICAgIC8vIERldGVybWluZSBpZiB0aGUgbW9kZWwgaGFzIGNoYW5nZWQgc2luY2UgdGhlIGxhc3QgYFwiY2hhbmdlXCJgIGV2ZW50LlxuICAgIC8vIElmIHlvdSBzcGVjaWZ5IGFuIGF0dHJpYnV0ZSBuYW1lLCBkZXRlcm1pbmUgaWYgdGhhdCBhdHRyaWJ1dGUgaGFzIGNoYW5nZWQuXG4gICAgaGFzQ2hhbmdlZDogZnVuY3Rpb24gKGF0dHIpIHtcbiAgICAgICAgaWYgKGF0dHIgPT0gbnVsbCkgcmV0dXJuICEhT2JqZWN0LmtleXModGhpcy5fY2hhbmdlZCkubGVuZ3RoO1xuICAgICAgICBpZiAoaGFzKHRoaXMuX2Rlcml2ZWQsIGF0dHIpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fZGVyaXZlZFthdHRyXS5kZXBMaXN0LnNvbWUoZnVuY3Rpb24gKGRlcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmhhc0NoYW5nZWQoZGVwKTtcbiAgICAgICAgICAgIH0sIHRoaXMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBoYXModGhpcy5fY2hhbmdlZCwgYXR0cik7XG4gICAgfSxcblxuICAgIC8vIFJldHVybiBhbiBvYmplY3QgY29udGFpbmluZyBhbGwgdGhlIGF0dHJpYnV0ZXMgdGhhdCBoYXZlIGNoYW5nZWQsIG9yXG4gICAgLy8gZmFsc2UgaWYgdGhlcmUgYXJlIG5vIGNoYW5nZWQgYXR0cmlidXRlcy4gVXNlZnVsIGZvciBkZXRlcm1pbmluZyB3aGF0XG4gICAgLy8gcGFydHMgb2YgYSB2aWV3IG5lZWQgdG8gYmUgdXBkYXRlZCBhbmQvb3Igd2hhdCBhdHRyaWJ1dGVzIG5lZWQgdG8gYmVcbiAgICAvLyBwZXJzaXN0ZWQgdG8gdGhlIHNlcnZlci4gVW5zZXQgYXR0cmlidXRlcyB3aWxsIGJlIHNldCB0byB1bmRlZmluZWQuXG4gICAgLy8gWW91IGNhbiBhbHNvIHBhc3MgYW4gYXR0cmlidXRlcyBvYmplY3QgdG8gZGlmZiBhZ2FpbnN0IHRoZSBtb2RlbCxcbiAgICAvLyBkZXRlcm1pbmluZyBpZiB0aGVyZSAqd291bGQgYmUqIGEgY2hhbmdlLlxuICAgIGNoYW5nZWRBdHRyaWJ1dGVzOiBmdW5jdGlvbiAoZGlmZikge1xuICAgICAgICBpZiAoIWRpZmYpIHJldHVybiB0aGlzLmhhc0NoYW5nZWQoKSA/IGNsb25lT2JqKHRoaXMuX2NoYW5nZWQpIDogZmFsc2U7XG4gICAgICAgIHZhciB2YWwsIGNoYW5nZWQgPSBmYWxzZTtcbiAgICAgICAgdmFyIG9sZCA9IHRoaXMuX2NoYW5naW5nID8gdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzIDogdGhpcy5hdHRyaWJ1dGVzO1xuICAgICAgICB2YXIgZGVmLCBpc0VxdWFsO1xuICAgICAgICBmb3IgKHZhciBhdHRyIGluIGRpZmYpIHtcbiAgICAgICAgICAgIGRlZiA9IHRoaXMuX2RlZmluaXRpb25bYXR0cl07XG4gICAgICAgICAgICBpZiAoIWRlZikgY29udGludWU7XG4gICAgICAgICAgICBpc0VxdWFsID0gdGhpcy5fZ2V0Q29tcGFyZUZvclR5cGUoZGVmLnR5cGUpO1xuICAgICAgICAgICAgaWYgKGlzRXF1YWwob2xkW2F0dHJdLCAodmFsID0gZGlmZlthdHRyXSkpKSBjb250aW51ZTtcbiAgICAgICAgICAgIChjaGFuZ2VkIHx8IChjaGFuZ2VkID0ge30pKVthdHRyXSA9IHZhbDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY2hhbmdlZDtcbiAgICB9LFxuXG4gICAgdG9KU09OOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlcmlhbGl6ZSgpO1xuICAgIH0sXG5cbiAgICB1bnNldDogZnVuY3Rpb24gKGF0dHJzLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgYXR0cnMgPSBBcnJheS5pc0FycmF5KGF0dHJzKSA/IGF0dHJzIDogW2F0dHJzXTtcbiAgICAgICAgYXR0cnMuZm9yRWFjaChmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICB2YXIgZGVmID0gc2VsZi5fZGVmaW5pdGlvbltrZXldO1xuICAgICAgICAgICAgaWYgKCFkZWYpIHJldHVybjtcbiAgICAgICAgICAgIHZhciB2YWw7XG4gICAgICAgICAgICBpZiAoZGVmLnJlcXVpcmVkKSB7XG4gICAgICAgICAgICAgICAgdmFsID0gcmVzdWx0KGRlZiwgJ2RlZmF1bHQnKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gc2VsZi5zZXQoa2V5LCB2YWwsIG9wdGlvbnMpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc2VsZi5zZXQoa2V5LCB2YWwsIGFzc2lnbih7fSwgb3B0aW9ucywge3Vuc2V0OiB0cnVlfSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgY2xlYXI6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgT2JqZWN0LmtleXModGhpcy5hdHRyaWJ1dGVzKS5mb3JFYWNoKGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHNlbGYudW5zZXQoa2V5LCBvcHRpb25zKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICBwcmV2aW91czogZnVuY3Rpb24gKGF0dHIpIHtcbiAgICAgICAgaWYgKGF0dHIgPT0gbnVsbCB8fCAhT2JqZWN0LmtleXModGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzKS5sZW5ndGgpIHJldHVybiBudWxsO1xuICAgICAgICByZXR1cm4gdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzW2F0dHJdO1xuICAgIH0sXG5cbiAgICAvLyBHZXQgZGVmYXVsdCB2YWx1ZXMgZm9yIGEgY2VydGFpbiB0eXBlXG4gICAgX2dldERlZmF1bHRGb3JUeXBlOiBmdW5jdGlvbiAodHlwZSkge1xuICAgICAgICB2YXIgZGF0YVR5cGUgPSB0aGlzLl9kYXRhVHlwZXNbdHlwZV07XG4gICAgICAgIHJldHVybiBkYXRhVHlwZSAmJiBkYXRhVHlwZVsnZGVmYXVsdCddO1xuICAgIH0sXG5cbiAgICAvLyBEZXRlcm1pbmUgd2hpY2ggY29tcGFyaXNvbiBhbGdvcml0aG0gdG8gdXNlIGZvciBjb21wYXJpbmcgYSBwcm9wZXJ0eVxuICAgIF9nZXRDb21wYXJlRm9yVHlwZTogZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgICAgdmFyIGRhdGFUeXBlID0gdGhpcy5fZGF0YVR5cGVzW3R5cGVdO1xuICAgICAgICBpZiAoZGF0YVR5cGUgJiYgZGF0YVR5cGUuY29tcGFyZSkgcmV0dXJuIGRhdGFUeXBlLmNvbXBhcmUuYmluZCh0aGlzKTtcbiAgICAgICAgcmV0dXJuIF9pc0VxdWFsOyAvLyBpZiBubyBjb21wYXJlIGZ1bmN0aW9uIGlzIGRlZmluZWQsIHVzZSBfLmlzRXF1YWxcbiAgICB9LFxuXG4gICAgX2dldE9uQ2hhbmdlRm9yVHlwZSA6IGZ1bmN0aW9uKHR5cGUpe1xuICAgICAgICB2YXIgZGF0YVR5cGUgPSB0aGlzLl9kYXRhVHlwZXNbdHlwZV07XG4gICAgICAgIGlmIChkYXRhVHlwZSAmJiBkYXRhVHlwZS5vbkNoYW5nZSkgcmV0dXJuIGRhdGFUeXBlLm9uQ2hhbmdlLmJpbmQodGhpcyk7XG4gICAgICAgIHJldHVybiBub29wO1xuICAgIH0sXG5cbiAgICAvLyBSdW4gdmFsaWRhdGlvbiBhZ2FpbnN0IHRoZSBuZXh0IGNvbXBsZXRlIHNldCBvZiBtb2RlbCBhdHRyaWJ1dGVzLFxuICAgIC8vIHJldHVybmluZyBgdHJ1ZWAgaWYgYWxsIGlzIHdlbGwuIE90aGVyd2lzZSwgZmlyZSBhbiBgXCJpbnZhbGlkXCJgIGV2ZW50LlxuICAgIF92YWxpZGF0ZTogZnVuY3Rpb24gKGF0dHJzLCBvcHRpb25zKSB7XG4gICAgICAgIGlmICghb3B0aW9ucy52YWxpZGF0ZSB8fCAhdGhpcy52YWxpZGF0ZSkgcmV0dXJuIHRydWU7XG4gICAgICAgIGF0dHJzID0gYXNzaWduKHt9LCB0aGlzLmF0dHJpYnV0ZXMsIGF0dHJzKTtcbiAgICAgICAgdmFyIGVycm9yID0gdGhpcy52YWxpZGF0aW9uRXJyb3IgPSB0aGlzLnZhbGlkYXRlKGF0dHJzLCBvcHRpb25zKSB8fCBudWxsO1xuICAgICAgICBpZiAoIWVycm9yKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgdGhpcy50cmlnZ2VyKCdpbnZhbGlkJywgdGhpcywgZXJyb3IsIGFzc2lnbihvcHRpb25zIHx8IHt9LCB7dmFsaWRhdGlvbkVycm9yOiBlcnJvcn0pKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0sXG5cbiAgICBfY3JlYXRlUHJvcGVydHlEZWZpbml0aW9uOiBmdW5jdGlvbiAobmFtZSwgZGVzYywgaXNTZXNzaW9uKSB7XG4gICAgICAgIHJldHVybiBjcmVhdGVQcm9wZXJ0eURlZmluaXRpb24odGhpcywgbmFtZSwgZGVzYywgaXNTZXNzaW9uKTtcbiAgICB9LFxuXG4gICAgLy8ganVzdCBtYWtlcyBmcmllbmRsaWVyIGVycm9ycyB3aGVuIHRyeWluZyB0byBkZWZpbmUgYSBuZXcgbW9kZWxcbiAgICAvLyBvbmx5IHVzZWQgd2hlbiBzZXR0aW5nIHVwIG9yaWdpbmFsIHByb3BlcnR5IGRlZmluaXRpb25zXG4gICAgX2Vuc3VyZVZhbGlkVHlwZTogZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgICAgcmV0dXJuIGluY2x1ZGVzKFsnc3RyaW5nJywgJ251bWJlcicsICdib29sZWFuJywgJ2FycmF5JywgJ29iamVjdCcsICdkYXRlJywgJ3N0YXRlJywgJ2FueSddXG4gICAgICAgICAgICAuY29uY2F0KE9iamVjdC5rZXlzKHRoaXMuX2RhdGFUeXBlcykpLCB0eXBlKSA/IHR5cGUgOiB1bmRlZmluZWQ7XG4gICAgfSxcblxuICAgIGdldEF0dHJpYnV0ZXM6IGZ1bmN0aW9uIChvcHRpb25zLCByYXcpIHtcbiAgICAgICAgb3B0aW9ucyA9IGFzc2lnbih7XG4gICAgICAgICAgICBzZXNzaW9uOiBmYWxzZSxcbiAgICAgICAgICAgIHByb3BzOiBmYWxzZSxcbiAgICAgICAgICAgIGRlcml2ZWQ6IGZhbHNlXG4gICAgICAgIH0sIG9wdGlvbnMgfHwge30pO1xuICAgICAgICB2YXIgcmVzID0ge307XG4gICAgICAgIHZhciB2YWwsIGRlZjtcbiAgICAgICAgZm9yICh2YXIgaXRlbSBpbiB0aGlzLl9kZWZpbml0aW9uKSB7XG4gICAgICAgICAgICBkZWYgPSB0aGlzLl9kZWZpbml0aW9uW2l0ZW1dO1xuICAgICAgICAgICAgaWYgKChvcHRpb25zLnNlc3Npb24gJiYgZGVmLnNlc3Npb24pIHx8IChvcHRpb25zLnByb3BzICYmICFkZWYuc2Vzc2lvbikpIHtcbiAgICAgICAgICAgICAgICB2YWwgPSByYXcgPyB0aGlzLl92YWx1ZXNbaXRlbV0gOiB0aGlzW2l0ZW1dO1xuICAgICAgICAgICAgICAgIGlmIChyYXcgJiYgdmFsICYmIGlzRnVuY3Rpb24odmFsLnNlcmlhbGl6ZSkpIHZhbCA9IHZhbC5zZXJpYWxpemUoKTtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbCA9PT0gJ3VuZGVmaW5lZCcpIHZhbCA9IHJlc3VsdChkZWYsICdkZWZhdWx0Jyk7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWwgIT09ICd1bmRlZmluZWQnKSByZXNbaXRlbV0gPSB2YWw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZGVyaXZlZCkge1xuICAgICAgICAgICAgZm9yICh2YXIgZGVyaXZlZEl0ZW0gaW4gdGhpcy5fZGVyaXZlZCkgcmVzW2Rlcml2ZWRJdGVtXSA9IHRoaXNbZGVyaXZlZEl0ZW1dO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfSxcblxuICAgIF9pbml0RGVyaXZlZDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgZm9yT3duKHRoaXMuX2Rlcml2ZWQsIGZ1bmN0aW9uICh2YWx1ZSwgbmFtZSkge1xuICAgICAgICAgICAgdmFyIGRlZiA9IHNlbGYuX2Rlcml2ZWRbbmFtZV07XG4gICAgICAgICAgICBkZWYuZGVwcyA9IGRlZi5kZXBMaXN0O1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBuZXdWYWwgPSBkZWYuZm4uY2FsbChzZWxmKTtcblxuICAgICAgICAgICAgICAgIGlmIChzZWxmLl9jYWNoZVtuYW1lXSAhPT0gbmV3VmFsIHx8ICFkZWYuY2FjaGUpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGRlZi5jYWNoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fcHJldmlvdXNBdHRyaWJ1dGVzW25hbWVdID0gc2VsZi5fY2FjaGVbbmFtZV07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgc2VsZi5fY2FjaGVbbmFtZV0gPSBuZXdWYWw7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYudHJpZ2dlcignY2hhbmdlOicgKyBuYW1lLCBzZWxmLCBzZWxmLl9jYWNoZVtuYW1lXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZGVmLmRlcHMuZm9yRWFjaChmdW5jdGlvbiAocHJvcFN0cmluZykge1xuICAgICAgICAgICAgICAgIHNlbGYuX2tleVRyZWUuYWRkKHByb3BTdHJpbmcsIHVwZGF0ZSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5vbignYWxsJywgZnVuY3Rpb24gKGV2ZW50TmFtZSkge1xuICAgICAgICAgICAgaWYgKGNoYW5nZVJFLnRlc3QoZXZlbnROYW1lKSkge1xuICAgICAgICAgICAgICAgIHNlbGYuX2tleVRyZWUuZ2V0KGV2ZW50TmFtZS5zcGxpdCgnOicpWzFdKS5mb3JFYWNoKGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgICAgICAgICBmbigpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LCB0aGlzKTtcbiAgICB9LFxuXG4gICAgX2dldERlcml2ZWRQcm9wZXJ0eTogZnVuY3Rpb24gKG5hbWUsIGZsdXNoQ2FjaGUpIHtcbiAgICAgICAgLy8gaXMgdGhpcyBhIGRlcml2ZWQgcHJvcGVydHkgdGhhdCBpcyBjYWNoZWRcbiAgICAgICAgaWYgKHRoaXMuX2Rlcml2ZWRbbmFtZV0uY2FjaGUpIHtcbiAgICAgICAgICAgIC8vc2V0IGlmIHRoaXMgaXMgdGhlIGZpcnN0IHRpbWUsIG9yIGZsdXNoQ2FjaGUgaXMgc2V0XG4gICAgICAgICAgICBpZiAoZmx1c2hDYWNoZSB8fCAhdGhpcy5fY2FjaGUuaGFzT3duUHJvcGVydHkobmFtZSkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9jYWNoZVtuYW1lXSA9IHRoaXMuX2Rlcml2ZWRbbmFtZV0uZm4uYXBwbHkodGhpcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fY2FjaGVbbmFtZV07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fZGVyaXZlZFtuYW1lXS5mbi5hcHBseSh0aGlzKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfaW5pdENvbGxlY3Rpb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBjb2xsO1xuICAgICAgICBpZiAoIXRoaXMuX2NvbGxlY3Rpb25zKSByZXR1cm47XG4gICAgICAgIGZvciAoY29sbCBpbiB0aGlzLl9jb2xsZWN0aW9ucykge1xuICAgICAgICAgICAgdGhpcy5fc2FmZVNldChjb2xsLCBuZXcgdGhpcy5fY29sbGVjdGlvbnNbY29sbF0obnVsbCwge3BhcmVudDogdGhpc30pKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfaW5pdENoaWxkcmVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBjaGlsZDtcbiAgICAgICAgaWYgKCF0aGlzLl9jaGlsZHJlbikgcmV0dXJuO1xuICAgICAgICBmb3IgKGNoaWxkIGluIHRoaXMuX2NoaWxkcmVuKSB7XG4gICAgICAgICAgICB0aGlzLl9zYWZlU2V0KGNoaWxkLCBuZXcgdGhpcy5fY2hpbGRyZW5bY2hpbGRdKHt9LCB7cGFyZW50OiB0aGlzfSkpO1xuICAgICAgICAgICAgdGhpcy5saXN0ZW5Ubyh0aGlzW2NoaWxkXSwgJ2FsbCcsIHRoaXMuX2dldENhY2hlZEV2ZW50QnViYmxpbmdIYW5kbGVyKGNoaWxkKSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLy8gUmV0dXJucyBhIGJvdW5kIGhhbmRsZXIgZm9yIGRvaW5nIGV2ZW50IGJ1YmJsaW5nIHdoaWxlXG4gICAgLy8gYWRkaW5nIGEgbmFtZSB0byB0aGUgY2hhbmdlIHN0cmluZy5cbiAgICBfZ2V0Q2FjaGVkRXZlbnRCdWJibGluZ0hhbmRsZXI6IGZ1bmN0aW9uIChwcm9wZXJ0eU5hbWUpIHtcbiAgICAgICAgaWYgKCF0aGlzLl9ldmVudEJ1YmJsaW5nSGFuZGxlckNhY2hlW3Byb3BlcnR5TmFtZV0pIHtcbiAgICAgICAgICAgIHRoaXMuX2V2ZW50QnViYmxpbmdIYW5kbGVyQ2FjaGVbcHJvcGVydHlOYW1lXSA9IGZ1bmN0aW9uIChuYW1lLCBtb2RlbCwgbmV3VmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAoY2hhbmdlUkUudGVzdChuYW1lKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnRyaWdnZXIoJ2NoYW5nZTonICsgcHJvcGVydHlOYW1lICsgJy4nICsgbmFtZS5zcGxpdCgnOicpWzFdLCBtb2RlbCwgbmV3VmFsdWUpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobmFtZSA9PT0gJ2NoYW5nZScpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy50cmlnZ2VyKCdjaGFuZ2UnLCB0aGlzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LmJpbmQodGhpcyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuX2V2ZW50QnViYmxpbmdIYW5kbGVyQ2FjaGVbcHJvcGVydHlOYW1lXTtcbiAgICB9LFxuXG4gICAgLy8gQ2hlY2sgdGhhdCBhbGwgcmVxdWlyZWQgYXR0cmlidXRlcyBhcmUgcHJlc2VudFxuICAgIF92ZXJpZnlSZXF1aXJlZDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgYXR0cnMgPSB0aGlzLmF0dHJpYnV0ZXM7IC8vIHNob3VsZCBpbmNsdWRlIHNlc3Npb25cbiAgICAgICAgZm9yICh2YXIgZGVmIGluIHRoaXMuX2RlZmluaXRpb24pIHtcbiAgICAgICAgICAgIGlmICh0aGlzLl9kZWZpbml0aW9uW2RlZl0ucmVxdWlyZWQgJiYgdHlwZW9mIGF0dHJzW2RlZl0gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0sXG5cbiAgICAvLyBleHBvc2Ugc2FmZVNldCBtZXRob2RcbiAgICBfc2FmZVNldDogZnVuY3Rpb24gc2FmZVNldChwcm9wZXJ0eSwgdmFsdWUpIHtcbiAgICAgICAgaWYgKHByb3BlcnR5IGluIHRoaXMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignRW5jb3VudGVyZWQgbmFtZXNwYWNlIGNvbGxpc2lvbiB3aGlsZSBzZXR0aW5nIGluc3RhbmNlIHByb3BlcnR5IGAnICsgcHJvcGVydHkgKyAnYCcpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXNbcHJvcGVydHldID0gdmFsdWU7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbn0pO1xuXG4vLyBnZXR0ZXIgZm9yIGF0dHJpYnV0ZXNcbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEJhc2UucHJvdG90eXBlLCB7XG4gICAgYXR0cmlidXRlczoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldEF0dHJpYnV0ZXMoe3Byb3BzOiB0cnVlLCBzZXNzaW9uOiB0cnVlfSk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGFsbDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAgIHNlc3Npb246IHRydWUsXG4gICAgICAgICAgICAgICAgcHJvcHM6IHRydWUsXG4gICAgICAgICAgICAgICAgZGVyaXZlZDogdHJ1ZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGlzU3RhdGU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7IHJldHVybiB0cnVlOyB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICgpIHsgfVxuICAgIH1cbn0pO1xuXG4vLyBoZWxwZXIgZm9yIGNyZWF0aW5nL3N0b3JpbmcgcHJvcGVydHkgZGVmaW5pdGlvbnMgYW5kIGNyZWF0aW5nXG4vLyBhcHByb3ByaWF0ZSBnZXR0ZXJzL3NldHRlcnNcbmZ1bmN0aW9uIGNyZWF0ZVByb3BlcnR5RGVmaW5pdGlvbihvYmplY3QsIG5hbWUsIGRlc2MsIGlzU2Vzc2lvbikge1xuICAgIHZhciBkZWYgPSBvYmplY3QuX2RlZmluaXRpb25bbmFtZV0gPSB7fTtcbiAgICB2YXIgdHlwZSwgZGVzY0FycmF5O1xuXG4gICAgaWYgKGlzU3RyaW5nKGRlc2MpKSB7XG4gICAgICAgIC8vIGdyYWIgb3VyIHR5cGUgaWYgYWxsIHdlJ3ZlIGdvdCBpcyBhIHN0cmluZ1xuICAgICAgICB0eXBlID0gb2JqZWN0Ll9lbnN1cmVWYWxpZFR5cGUoZGVzYyk7XG4gICAgICAgIGlmICh0eXBlKSBkZWYudHlwZSA9IHR5cGU7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy9UcmFuc2Zvcm0gYXJyYXkgb2YgWyd0eXBlJywgcmVxdWlyZWQsIGRlZmF1bHRdIHRvIG9iamVjdCBmb3JtXG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KGRlc2MpKSB7XG4gICAgICAgICAgICBkZXNjQXJyYXkgPSBkZXNjO1xuICAgICAgICAgICAgZGVzYyA9IHtcbiAgICAgICAgICAgICAgICB0eXBlOiBkZXNjQXJyYXlbMF0sXG4gICAgICAgICAgICAgICAgcmVxdWlyZWQ6IGRlc2NBcnJheVsxXSxcbiAgICAgICAgICAgICAgICAnZGVmYXVsdCc6IGRlc2NBcnJheVsyXVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHR5cGUgPSBvYmplY3QuX2Vuc3VyZVZhbGlkVHlwZShkZXNjLnR5cGUpO1xuICAgICAgICBpZiAodHlwZSkgZGVmLnR5cGUgPSB0eXBlO1xuXG4gICAgICAgIGlmIChkZXNjLnJlcXVpcmVkKSBkZWYucmVxdWlyZWQgPSB0cnVlO1xuXG4gICAgICAgIGlmIChkZXNjWydkZWZhdWx0J10gJiYgdHlwZW9mIGRlc2NbJ2RlZmF1bHQnXSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1RoZSBkZWZhdWx0IHZhbHVlIGZvciAnICsgbmFtZSArICcgY2Fubm90IGJlIGFuIG9iamVjdC9hcnJheSwgbXVzdCBiZSBhIHZhbHVlIG9yIGEgZnVuY3Rpb24gd2hpY2ggcmV0dXJucyBhIHZhbHVlL29iamVjdC9hcnJheScpO1xuICAgICAgICB9XG5cbiAgICAgICAgZGVmWydkZWZhdWx0J10gPSBkZXNjWydkZWZhdWx0J107XG5cbiAgICAgICAgZGVmLmFsbG93TnVsbCA9IGRlc2MuYWxsb3dOdWxsID8gZGVzYy5hbGxvd051bGwgOiBmYWxzZTtcbiAgICAgICAgaWYgKGRlc2Muc2V0T25jZSkgZGVmLnNldE9uY2UgPSB0cnVlO1xuICAgICAgICBpZiAoZGVmLnJlcXVpcmVkICYmIGRlZlsnZGVmYXVsdCddID09PSB1bmRlZmluZWQgJiYgIWRlZi5zZXRPbmNlKSBkZWZbJ2RlZmF1bHQnXSA9IG9iamVjdC5fZ2V0RGVmYXVsdEZvclR5cGUodHlwZSk7XG4gICAgICAgIGRlZi50ZXN0ID0gZGVzYy50ZXN0O1xuICAgICAgICBkZWYudmFsdWVzID0gZGVzYy52YWx1ZXM7XG4gICAgfVxuICAgIGlmIChpc1Nlc3Npb24pIGRlZi5zZXNzaW9uID0gdHJ1ZTtcblxuICAgIGlmICghdHlwZSkge1xuICAgICAgICB0eXBlID0gaXNTdHJpbmcoZGVzYykgPyBkZXNjIDogZGVzYy50eXBlO1xuICAgICAgICAvLyBUT0RPOiBzdGFydCB0aHJvd2luZyBhIFR5cGVFcnJvciBpbiBmdXR1cmUgbWFqb3IgdmVyc2lvbnMgaW5zdGVhZCBvZiB3YXJuaW5nXG4gICAgICAgIGNvbnNvbGUud2FybignSW52YWxpZCBkYXRhIHR5cGUgb2YgYCcgKyB0eXBlICsgJ2AgZm9yIGAnICsgbmFtZSArICdgIHByb3BlcnR5LiBVc2Ugb25lIG9mIHRoZSBkZWZhdWx0IHR5cGVzIG9yIGRlZmluZSB5b3VyIG93bicpO1xuICAgIH1cblxuICAgIC8vIGRlZmluZSBhIGdldHRlci9zZXR0ZXIgb24gdGhlIHByb3RvdHlwZVxuICAgIC8vIGJ1dCB0aGV5IGdldC9zZXQgb24gdGhlIGluc3RhbmNlXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iamVjdCwgbmFtZSwge1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWwpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0KG5hbWUsIHZhbCk7XG4gICAgICAgIH0sXG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKCF0aGlzLl92YWx1ZXMpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcignWW91IG1heSBiZSB0cnlpbmcgdG8gYGV4dGVuZGAgYSBzdGF0ZSBvYmplY3Qgd2l0aCBcIicgKyBuYW1lICsgJ1wiIHdoaWNoIGhhcyBiZWVuIGRlZmluZWQgaW4gYHByb3BzYCBvbiB0aGUgb2JqZWN0IGJlaW5nIGV4dGVuZGVkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgdmFsdWUgPSB0aGlzLl92YWx1ZXNbbmFtZV07XG4gICAgICAgICAgICB2YXIgdHlwZURlZiA9IHRoaXMuX2RhdGFUeXBlc1tkZWYudHlwZV07XG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlRGVmICYmIHR5cGVEZWYuZ2V0KSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdHlwZURlZi5nZXQodmFsdWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgZGVmYXVsdFZhbHVlID0gcmVzdWx0KGRlZiwgJ2RlZmF1bHQnKTtcbiAgICAgICAgICAgIHRoaXMuX3ZhbHVlc1tuYW1lXSA9IGRlZmF1bHRWYWx1ZTtcbiAgICAgICAgICAgIC8vIElmIHdlJ3ZlIHNldCBhIGRlZmF1bHRWYWx1ZSwgZmlyZSBhIGNoYW5nZSBoYW5kbGVyIGVmZmVjdGl2ZWx5IG1hcmtpbmdcbiAgICAgICAgICAgIC8vIGl0cyBjaGFuZ2UgZnJvbSB1bmRlZmluZWQgdG8gdGhlIGRlZmF1bHQgdmFsdWUuXG4gICAgICAgICAgICBpZiAodHlwZW9mIGRlZmF1bHRWYWx1ZSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICB2YXIgb25DaGFuZ2UgPSB0aGlzLl9nZXRPbkNoYW5nZUZvclR5cGUoZGVmLnR5cGUpO1xuICAgICAgICAgICAgICAgIG9uQ2hhbmdlKGRlZmF1bHRWYWx1ZSwgdmFsdWUsIG5hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGRlZmF1bHRWYWx1ZTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGRlZjtcbn1cblxuLy8gaGVscGVyIGZvciBjcmVhdGluZyBkZXJpdmVkIHByb3BlcnR5IGRlZmluaXRpb25zXG5mdW5jdGlvbiBjcmVhdGVEZXJpdmVkUHJvcGVydHkobW9kZWxQcm90bywgbmFtZSwgZGVmaW5pdGlvbikge1xuICAgIHZhciBkZWYgPSBtb2RlbFByb3RvLl9kZXJpdmVkW25hbWVdID0ge1xuICAgICAgICBmbjogaXNGdW5jdGlvbihkZWZpbml0aW9uKSA/IGRlZmluaXRpb24gOiBkZWZpbml0aW9uLmZuLFxuICAgICAgICBjYWNoZTogKGRlZmluaXRpb24uY2FjaGUgIT09IGZhbHNlKSxcbiAgICAgICAgZGVwTGlzdDogZGVmaW5pdGlvbi5kZXBzIHx8IFtdXG4gICAgfTtcblxuICAgIC8vIGFkZCB0byBvdXIgc2hhcmVkIGRlcGVuZGVuY3kgbGlzdFxuICAgIGRlZi5kZXBMaXN0LmZvckVhY2goZnVuY3Rpb24gKGRlcCkge1xuICAgICAgICBtb2RlbFByb3RvLl9kZXBzW2RlcF0gPSB1bmlvbihtb2RlbFByb3RvLl9kZXBzW2RlcF0gfHwgW10sIFtuYW1lXSk7XG4gICAgfSk7XG5cbiAgICAvLyBkZWZpbmVkIGEgdG9wLWxldmVsIGdldHRlciBmb3IgZGVyaXZlZCBuYW1lc1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShtb2RlbFByb3RvLCBuYW1lLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2dldERlcml2ZWRQcm9wZXJ0eShuYW1lKTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYFwiICsgbmFtZSArIFwiYCBpcyBhIGRlcml2ZWQgcHJvcGVydHksIGl0IGNhbid0IGJlIHNldCBkaXJlY3RseS5cIik7XG4gICAgICAgIH1cbiAgICB9KTtcbn1cblxudmFyIGRhdGFUeXBlcyA9IHtcbiAgICBzdHJpbmc6IHtcbiAgICAgICAgJ2RlZmF1bHQnOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGRhdGU6IHtcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAobmV3VmFsKSB7XG4gICAgICAgICAgICB2YXIgbmV3VHlwZTtcbiAgICAgICAgICAgIGlmIChuZXdWYWwgPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIG5ld1R5cGUgPSB0eXBlb2YgbnVsbDtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIWlzRGF0ZShuZXdWYWwpKSB7XG4gICAgICAgICAgICAgICAgdmFyIGVyciA9IG51bGw7XG4gICAgICAgICAgICAgICAgdmFyIGRhdGVWYWwgPSBuZXcgRGF0ZShuZXdWYWwpLnZhbHVlT2YoKTtcbiAgICAgICAgICAgICAgICBpZiAoaXNOYU4oZGF0ZVZhbCkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhlIG5ld1ZhbCBjYW50IGJlIHBhcnNlZCwgdGhlbiB0cnkgcGFyc2VJbnQgZmlyc3RcbiAgICAgICAgICAgICAgICAgICAgZGF0ZVZhbCA9IG5ldyBEYXRlKHBhcnNlSW50KG5ld1ZhbCwgMTApKS52YWx1ZU9mKCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpc05hTihkYXRlVmFsKSkgZXJyID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbmV3VmFsID0gZGF0ZVZhbDtcbiAgICAgICAgICAgICAgICBuZXdUeXBlID0gJ2RhdGUnO1xuICAgICAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgbmV3VHlwZSA9IHR5cGVvZiBuZXdWYWw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBuZXdUeXBlID0gJ2RhdGUnO1xuICAgICAgICAgICAgICAgIG5ld1ZhbCA9IG5ld1ZhbC52YWx1ZU9mKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgdmFsOiBuZXdWYWwsXG4gICAgICAgICAgICAgICAgdHlwZTogbmV3VHlwZVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAodmFsKSB7XG4gICAgICAgICAgICBpZiAodmFsID09IG51bGwpIHsgcmV0dXJuIHZhbDsgfVxuICAgICAgICAgICAgcmV0dXJuIG5ldyBEYXRlKHZhbCk7XG4gICAgICAgIH0sXG4gICAgICAgICdkZWZhdWx0JzogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBEYXRlKCk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGFycmF5OiB7XG4gICAgICAgIHNldDogZnVuY3Rpb24gKG5ld1ZhbCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB2YWw6IG5ld1ZhbCxcbiAgICAgICAgICAgICAgICB0eXBlOiBBcnJheS5pc0FycmF5KG5ld1ZhbCkgPyAnYXJyYXknIDogdHlwZW9mIG5ld1ZhbFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgJ2RlZmF1bHQnOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgIH1cbiAgICB9LFxuICAgIG9iamVjdDoge1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChuZXdWYWwpIHtcbiAgICAgICAgICAgIHZhciBuZXdUeXBlID0gdHlwZW9mIG5ld1ZhbDtcbiAgICAgICAgICAgIC8vIHdlIGhhdmUgdG8gaGF2ZSBhIHdheSBvZiBzdXBwb3J0aW5nIFwibWlzc2luZ1wiIG9iamVjdHMuXG4gICAgICAgICAgICAvLyBOdWxsIGlzIGFuIG9iamVjdCwgYnV0IHNldHRpbmcgYSB2YWx1ZSB0byB1bmRlZmluZWRcbiAgICAgICAgICAgIC8vIHNob3VsZCB3b3JrIHRvbywgSU1PLiBXZSBqdXN0IG92ZXJyaWRlIGl0LCBpbiB0aGF0IGNhc2UuXG4gICAgICAgICAgICBpZiAobmV3VHlwZSAhPT0gJ29iamVjdCcgJiYgbmV3VmFsID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBuZXdWYWwgPSBudWxsO1xuICAgICAgICAgICAgICAgIG5ld1R5cGUgPSAnb2JqZWN0JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgdmFsOiBuZXdWYWwsXG4gICAgICAgICAgICAgICAgdHlwZTogbmV3VHlwZVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgJ2RlZmF1bHQnOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4ge307XG4gICAgICAgIH1cbiAgICB9LFxuICAgIC8vIHRoZSBgc3RhdGVgIGRhdGEgdHlwZSBpcyBhIGJpdCBzcGVjaWFsIGluIHRoYXQgc2V0dGluZyBpdCBzaG91bGRcbiAgICAvLyBhbHNvIGJ1YmJsZSBldmVudHNcbiAgICBzdGF0ZToge1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChuZXdWYWwpIHtcbiAgICAgICAgICAgIHZhciBpc0luc3RhbmNlID0gbmV3VmFsIGluc3RhbmNlb2YgQmFzZSB8fCAobmV3VmFsICYmIG5ld1ZhbC5pc1N0YXRlKTtcbiAgICAgICAgICAgIGlmIChpc0luc3RhbmNlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsOiBuZXdWYWwsXG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdzdGF0ZSdcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICB2YWw6IG5ld1ZhbCxcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogdHlwZW9mIG5ld1ZhbFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGNvbXBhcmU6IGZ1bmN0aW9uIChjdXJyZW50VmFsLCBuZXdWYWwpIHtcbiAgICAgICAgICAgIHJldHVybiBjdXJyZW50VmFsID09PSBuZXdWYWw7XG4gICAgICAgIH0sXG5cbiAgICAgICAgb25DaGFuZ2UgOiBmdW5jdGlvbihuZXdWYWwsIHByZXZpb3VzVmFsLCBhdHRyaWJ1dGVOYW1lKXtcbiAgICAgICAgICAgIC8vIGlmIHRoaXMgaGFzIGNoYW5nZWQgd2Ugd2FudCB0byBhbHNvIGhhbmRsZVxuICAgICAgICAgICAgLy8gZXZlbnQgcHJvcGFnYXRpb25cbiAgICAgICAgICAgIGlmIChwcmV2aW91c1ZhbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuc3RvcExpc3RlbmluZyhwcmV2aW91c1ZhbCwgJ2FsbCcsIHRoaXMuX2dldENhY2hlZEV2ZW50QnViYmxpbmdIYW5kbGVyKGF0dHJpYnV0ZU5hbWUpKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKG5ld1ZhbCAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5saXN0ZW5UbyhuZXdWYWwsICdhbGwnLCB0aGlzLl9nZXRDYWNoZWRFdmVudEJ1YmJsaW5nSGFuZGxlcihhdHRyaWJ1dGVOYW1lKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vLyB0aGUgZXh0ZW5kIG1ldGhvZCB1c2VkIHRvIGV4dGVuZCBwcm90b3R5cGVzLCBtYWludGFpbiBpbmhlcml0YW5jZSBjaGFpbnMgZm9yIGluc3RhbmNlb2Zcbi8vIGFuZCBhbGxvdyBmb3IgYWRkaXRpb25zIHRvIHRoZSBtb2RlbCBkZWZpbml0aW9ucy5cbmZ1bmN0aW9uIGV4dGVuZChwcm90b1Byb3BzKSB7XG4gICAgLypqc2hpbnQgdmFsaWR0aGlzOnRydWUqL1xuICAgIHZhciBwYXJlbnQgPSB0aGlzO1xuICAgIHZhciBjaGlsZDtcblxuICAgIC8vIFRoZSBjb25zdHJ1Y3RvciBmdW5jdGlvbiBmb3IgdGhlIG5ldyBzdWJjbGFzcyBpcyBlaXRoZXIgZGVmaW5lZCBieSB5b3VcbiAgICAvLyAodGhlIFwiY29uc3RydWN0b3JcIiBwcm9wZXJ0eSBpbiB5b3VyIGBleHRlbmRgIGRlZmluaXRpb24pLCBvciBkZWZhdWx0ZWRcbiAgICAvLyBieSB1cyB0byBzaW1wbHkgY2FsbCB0aGUgcGFyZW50J3MgY29uc3RydWN0b3IuXG4gICAgaWYgKHByb3RvUHJvcHMgJiYgcHJvdG9Qcm9wcy5oYXNPd25Qcm9wZXJ0eSgnY29uc3RydWN0b3InKSkge1xuICAgICAgICBjaGlsZCA9IHByb3RvUHJvcHMuY29uc3RydWN0b3I7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgY2hpbGQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gcGFyZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gQWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjb25zdHJ1Y3RvciBmdW5jdGlvbiBmcm9tIHBhcmVudFxuICAgIGFzc2lnbihjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIFNldCB0aGUgcHJvdG90eXBlIGNoYWluIHRvIGluaGVyaXQgZnJvbSBgcGFyZW50YCwgd2l0aG91dCBjYWxsaW5nXG4gICAgLy8gYHBhcmVudGAncyBjb25zdHJ1Y3RvciBmdW5jdGlvbi5cbiAgICB2YXIgU3Vycm9nYXRlID0gZnVuY3Rpb24gKCkgeyB0aGlzLmNvbnN0cnVjdG9yID0gY2hpbGQ7IH07XG4gICAgU3Vycm9nYXRlLnByb3RvdHlwZSA9IHBhcmVudC5wcm90b3R5cGU7XG4gICAgY2hpbGQucHJvdG90eXBlID0gbmV3IFN1cnJvZ2F0ZSgpO1xuXG4gICAgLy8gc2V0IHByb3RvdHlwZSBsZXZlbCBvYmplY3RzXG4gICAgY2hpbGQucHJvdG90eXBlLl9kZXJpdmVkID0gIGFzc2lnbih7fSwgcGFyZW50LnByb3RvdHlwZS5fZGVyaXZlZCk7XG4gICAgY2hpbGQucHJvdG90eXBlLl9kZXBzID0gYXNzaWduKHt9LCBwYXJlbnQucHJvdG90eXBlLl9kZXBzKTtcbiAgICBjaGlsZC5wcm90b3R5cGUuX2RlZmluaXRpb24gPSBhc3NpZ24oe30sIHBhcmVudC5wcm90b3R5cGUuX2RlZmluaXRpb24pO1xuICAgIGNoaWxkLnByb3RvdHlwZS5fY29sbGVjdGlvbnMgPSBhc3NpZ24oe30sIHBhcmVudC5wcm90b3R5cGUuX2NvbGxlY3Rpb25zKTtcbiAgICBjaGlsZC5wcm90b3R5cGUuX2NoaWxkcmVuID0gYXNzaWduKHt9LCBwYXJlbnQucHJvdG90eXBlLl9jaGlsZHJlbik7XG4gICAgY2hpbGQucHJvdG90eXBlLl9kYXRhVHlwZXMgPSBhc3NpZ24oe30sIHBhcmVudC5wcm90b3R5cGUuX2RhdGFUeXBlcyB8fCBkYXRhVHlwZXMpO1xuXG4gICAgLy8gTWl4IGluIGFsbCBwcm90b3R5cGUgcHJvcGVydGllcyB0byB0aGUgc3ViY2xhc3MgaWYgc3VwcGxpZWQuXG4gICAgaWYgKHByb3RvUHJvcHMpIHtcbiAgICAgICAgdmFyIG9taXRGcm9tRXh0ZW5kID0gW1xuICAgICAgICAgICAgJ2RhdGFUeXBlcycsICdwcm9wcycsICdzZXNzaW9uJywgJ2Rlcml2ZWQnLCAnY29sbGVjdGlvbnMnLCAnY2hpbGRyZW4nXG4gICAgICAgIF07XG4gICAgICAgIGZvcih2YXIgaSA9IDA7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHZhciBkZWYgPSBhcmd1bWVudHNbaV07XG4gICAgICAgICAgICBpZiAoZGVmLmRhdGFUeXBlcykge1xuICAgICAgICAgICAgICAgIGZvck93bihkZWYuZGF0YVR5cGVzLCBmdW5jdGlvbiAoZGVmLCBuYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIGNoaWxkLnByb3RvdHlwZS5fZGF0YVR5cGVzW25hbWVdID0gZGVmO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRlZi5wcm9wcykge1xuICAgICAgICAgICAgICAgIGZvck93bihkZWYucHJvcHMsIGZ1bmN0aW9uIChkZWYsIG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgY3JlYXRlUHJvcGVydHlEZWZpbml0aW9uKGNoaWxkLnByb3RvdHlwZSwgbmFtZSwgZGVmKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChkZWYuc2Vzc2lvbikge1xuICAgICAgICAgICAgICAgIGZvck93bihkZWYuc2Vzc2lvbiwgZnVuY3Rpb24gKGRlZiwgbmFtZSkge1xuICAgICAgICAgICAgICAgICAgICBjcmVhdGVQcm9wZXJ0eURlZmluaXRpb24oY2hpbGQucHJvdG90eXBlLCBuYW1lLCBkZWYsIHRydWUpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRlZi5kZXJpdmVkKSB7XG4gICAgICAgICAgICAgICAgZm9yT3duKGRlZi5kZXJpdmVkLCBmdW5jdGlvbiAoZGVmLCBuYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZURlcml2ZWRQcm9wZXJ0eShjaGlsZC5wcm90b3R5cGUsIG5hbWUsIGRlZik7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZGVmLmNvbGxlY3Rpb25zKSB7XG4gICAgICAgICAgICAgICAgZm9yT3duKGRlZi5jb2xsZWN0aW9ucywgZnVuY3Rpb24gKGNvbnN0cnVjdG9yLCBuYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIGNoaWxkLnByb3RvdHlwZS5fY29sbGVjdGlvbnNbbmFtZV0gPSBjb25zdHJ1Y3RvcjtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChkZWYuY2hpbGRyZW4pIHtcbiAgICAgICAgICAgICAgICBmb3JPd24oZGVmLmNoaWxkcmVuLCBmdW5jdGlvbiAoY29uc3RydWN0b3IsIG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgY2hpbGQucHJvdG90eXBlLl9jaGlsZHJlbltuYW1lXSA9IGNvbnN0cnVjdG9yO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXNzaWduKGNoaWxkLnByb3RvdHlwZSwgb21pdChkZWYsIG9taXRGcm9tRXh0ZW5kKSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBTZXQgYSBjb252ZW5pZW5jZSBwcm9wZXJ0eSBpbiBjYXNlIHRoZSBwYXJlbnQncyBwcm90b3R5cGUgaXMgbmVlZGVkXG4gICAgLy8gbGF0ZXIuXG4gICAgY2hpbGQuX19zdXBlcl9fID0gcGFyZW50LnByb3RvdHlwZTtcblxuICAgIHJldHVybiBjaGlsZDtcbn1cblxuQmFzZS5leHRlbmQgPSBleHRlbmQ7XG5cbi8vIE91ciBtYWluIGV4cG9ydHNcbm1vZHVsZS5leHBvcnRzID0gQmFzZTtcbiJdLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTsiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///ef45\n")}}]);

FIXME found
Open

(window.webpackJsonp=window.webpackJsonp||[]).push([["npm.ampersand-state"],{ef45:function(module,exports,__webpack_require__){"use strict";eval("\n/*$AMPERSAND_VERSION*/\nvar uniqueId = __webpack_require__(/*! lodash/uniqueId */ \"6d0d\");\nvar assign = __webpack_require__(/*! lodash/assign */ \"5ad5\");\nvar cloneObj = function(obj) { return assign({}, obj); };\nvar omit = __webpack_require__(/*! lodash/omit */ \"4633\");\nvar escape = __webpack_require__(/*! lodash/escape */ \"740c\");\nvar forOwn = __webpack_require__(/*! lodash/forOwn */ \"436f\");\nvar includes = __webpack_require__(/*! lodash/includes */ \"e2c7\");\nvar isString = __webpack_require__(/*! lodash/isString */ \"5fa3\");\nvar isObject = __webpack_require__(/*! lodash/isObject */ \"d3a8\");\nvar isDate = __webpack_require__(/*! lodash/isDate */ \"7f93\");\nvar isFunction = __webpack_require__(/*! lodash/isFunction */ \"f3b0\");\nvar _isEqual = __webpack_require__(/*! lodash/isEqual */ \"f8a3\"); // to avoid shadowing\nvar has = __webpack_require__(/*! lodash/has */ \"b055\");\nvar result = __webpack_require__(/*! lodash/result */ \"80c9\");\nvar union = __webpack_require__(/*! lodash/union */ \"c80f\");\nvar Events = __webpack_require__(/*! ampersand-events */ \"13c2\");\nvar KeyTree = __webpack_require__(/*! key-tree-store */ \"8849\");\nvar arrayNext = __webpack_require__(/*! array-next */ \"d1bb\");\nvar changeRE = /^change:/;\nvar noop = function () {};\n\nfunction Base(attrs, options) {\n    options || (options = {});\n    this.cid || (this.cid = uniqueId('state'));\n    this._events = {};\n    this._values = {};\n    this._eventBubblingHandlerCache = {};\n    this._definition = Object.create(this._definition);\n    if (options.parse) attrs = this.parse(attrs, options);\n    this.parent = options.parent;\n    this.collection = options.collection;\n    this._keyTree = new KeyTree();\n    this._initCollections();\n    this._initChildren();\n    this._cache = {};\n    this._previousAttributes = {};\n    if (attrs) this.set(attrs, assign({silent: true, initial: true}, options));\n    this._changed = {};\n    if (this._derived) this._initDerived();\n    if (options.init !== false) this.initialize.apply(this, arguments);\n}\n\nassign(Base.prototype, Events, {\n    // can be allow, ignore, reject\n    extraProperties: 'ignore',\n\n    idAttribute: 'id',\n\n    namespaceAttribute: 'namespace',\n\n    typeAttribute: 'modelType',\n\n    // Stubbed out to be overwritten\n    initialize: function () {\n        return this;\n    },\n\n    // Get ID of model per configuration.\n    // Should *always* be how ID is determined by other code.\n    getId: function () {\n        return this[this.idAttribute];\n    },\n\n    // Get namespace of model per configuration.\n    // Should *always* be how namespace is determined by other code.\n    getNamespace: function () {\n        return this[this.namespaceAttribute];\n    },\n\n    // Get type of model per configuration.\n    // Should *always* be how type is determined by other code.\n    getType: function () {\n        return this[this.typeAttribute];\n    },\n\n    // A model is new if it has never been saved to the server, and lacks an id.\n    isNew: function () {\n        return this.getId() == null;\n    },\n\n    // get HTML-escaped value of attribute\n    escape: function (attr) {\n        return escape(this.get(attr));\n    },\n\n    // Check if the model is currently in a valid state.\n    isValid: function (options) {\n        return this._validate({}, assign(options || {}, { validate: true }));\n    },\n\n    // Parse can be used remap/restructure/rename incoming properties\n    // before they are applied to attributes.\n    parse: function (resp, options) {\n        //jshint unused:false\n        return resp;\n    },\n\n    // Serialize is the inverse of `parse` it lets you massage data\n    // on the way out. Before, sending to server, for example.\n    serialize: function (options) {\n        var attrOpts = assign({props: true}, options);\n        var res = this.getAttributes(attrOpts, true);\n        \n        var setFromSerializedValue = function (value, key) {\n\t        res[key] = this[key].serialize();\n        }.bind(this);\n        \n        forOwn(this._children, setFromSerializedValue);\n        forOwn(this._collections, setFromSerializedValue);\n        return res;\n    },\n\n    // Main set method used by generated setters/getters and can\n    // be used directly if you need to pass options or set multiple\n    // properties at once.\n    set: function (key, value, options) {\n        var self = this;\n        var extraProperties = this.extraProperties;\n        var wasChanging, changeEvents, newType, newVal, def, cast, err, attr,\n            attrs, dataType, silent, unset, currentVal, initial, hasChanged, isEqual, onChange;\n\n        // Handle both `\"key\", value` and `{key: value}` -style arguments.\n        if (isObject(key) || key === null) {\n            attrs = key;\n            options = value;\n        } else {\n            attrs = {};\n            attrs[key] = value;\n        }\n\n        options = options || {};\n\n        if (!this._validate(attrs, options)) return false;\n\n        // Extract attributes and options.\n        unset = options.unset;\n        silent = options.silent;\n        initial = options.initial;\n\n        // Initialize change tracking.\n        wasChanging = this._changing;\n        this._changing = true;\n        changeEvents = [];\n\n        // if not already changing, store previous\n        if (initial) {\n            this._previousAttributes = {};\n        } else if (!wasChanging) {\n            this._previousAttributes = this.attributes;\n            this._changed = {};\n        }\n\n        // For each `set` attribute...\n        for (var i = 0, keys = Object.keys(attrs), len = keys.length; i < len; i++) {\n            attr = keys[i];\n            newVal = attrs[attr];\n            newType = typeof newVal;\n            currentVal = this._values[attr];\n            def = this._definition[attr];\n\n            if (!def) {\n                // if this is a child model or collection\n                if (this._children[attr] || this._collections[attr]) {\n                    if (!isObject(newVal)) {\n                        newVal = {};\n                    }\n\n                    this[attr].set(newVal, options);\n                    continue;\n                } else if (extraProperties === 'ignore') {\n                    continue;\n                } else if (extraProperties === 'reject') {\n                    throw new TypeError('No \"' + attr + '\" property defined on ' + (this.type || 'this') + ' model and extraProperties not set to \"ignore\" or \"allow\"');\n                } else if (extraProperties === 'allow') {\n                    def = this._createPropertyDefinition(attr, 'any');\n                } else if (extraProperties) {\n                    throw new TypeError('Invalid value for extraProperties: \"' + extraProperties + '\"');\n                }\n            }\n\n            isEqual = this._getCompareForType(def.type);\n            onChange = this._getOnChangeForType(def.type);\n            dataType = this._dataTypes[def.type];\n\n            // check type if we have one\n            if (dataType && dataType.set) {\n                cast = dataType.set(newVal);\n                newVal = cast.val;\n                newType = cast.type;\n            }\n\n            // If we've defined a test, run it\n            if (def.test) {\n                err = def.test.call(this, newVal, newType);\n                if (err) {\n                    throw new TypeError('Property \\'' + attr + '\\' failed validation with error: ' + err);\n                }\n            }\n\n            // If we are required but undefined, throw error.\n            // If we are null and are not allowing null, throw error\n            // If we have a defined type and the new type doesn't match, and we are not null, throw error.\n            // If we require specific value and new one is not one of them, throw error (unless it has default value or we're unsetting it with undefined).\n\n            if (newVal === undefined && def.required) {\n                throw new TypeError('Required property \\'' + attr + '\\' must be of type ' + def.type + '. Tried to set ' + newVal);\n            }\n            if (newVal === null && def.required && !def.allowNull) {\n                throw new TypeError('Property \\'' + attr + '\\' must be of type ' + def.type + ' (cannot be null). Tried to set ' + newVal);\n            }\n            if ((def.type && def.type !== 'any' && def.type !== newType) && newVal !== null && newVal !== undefined) {\n                throw new TypeError('Property \\'' + attr + '\\' must be of type ' + def.type + '. Tried to set ' + newVal);\n            }\n            if (def.values && !includes(def.values, newVal)) {\n                var defaultValue = result(def, 'default');\n                if (unset && defaultValue !== undefined) {\n                    newVal = defaultValue;\n                } else if (!unset || (unset && newVal !== undefined)) {\n                    throw new TypeError('Property \\'' + attr + '\\' must be one of values: ' + def.values.join(', ') + '. Tried to set ' + newVal);\n                }\n            }\n\n            // We know this has 'changed' if it's the initial set, so skip a potentially expensive isEqual check.\n            hasChanged = initial || !isEqual(currentVal, newVal, attr);\n\n            // enforce `setOnce` for properties if set\n            if (def.setOnce && currentVal !== undefined && hasChanged) {\n                throw new TypeError('Property \\'' + attr + '\\' can only be set once.');\n            }\n\n            // set/unset attributes.\n            // If this is not the initial set, keep track of changed attributes\n            // and push to changeEvents array so we can fire events.\n            if (hasChanged) {\n\n                // This fires no matter what, even on initial set.\n                onChange(newVal, currentVal, attr);\n\n                // If this is a change (not an initial set), mark the change.\n                // Note it's impossible to unset on the initial set (it will already be unset),\n                // so we only include that logic here.\n                if (!initial) {\n                    this._changed[attr] = newVal;\n                    this._previousAttributes[attr] = currentVal;\n                    if (unset) {\n                        // FIXME delete is very slow. Can we get away with setting to undefined?\n                        delete this._values[attr];\n                    }\n                    if (!silent) {\n                        changeEvents.push({prev: currentVal, val: newVal, key: attr});\n                    }\n                }\n                if (!unset) {\n                    this._values[attr] = newVal;\n                }\n            } else {\n                // Not changed\n                // FIXME delete is very slow. Can we get away with setting to undefined?\n                delete this._changed[attr];\n            }\n        }\n\n        // Fire events. This array is not populated if we are told to be silent.\n        if (changeEvents.length) this._pending = true;\n        changeEvents.forEach(function (change) {\n            self.trigger('change:' + change.key, self, change.val, options);\n        });\n\n        // You might be wondering why there's a `while` loop here. Changes can\n        // be recursively nested within `\"change\"` events.\n        if (wasChanging) return this;\n        while (this._pending) {\n            this._pending = false;\n            this.trigger('change', this, options);\n        }\n        this._pending = false;\n        this._changing = false;\n        return this;\n    },\n\n    get: function (attr) {\n        return this[attr];\n    },\n\n    // Toggle boolean properties or properties that have a `values`\n    // array in its definition.\n    toggle: function (property) {\n        var def = this._definition[property];\n        if (def.type === 'boolean') {\n            // if it's a bool, just flip it\n            this[property] = !this[property];\n        } else if (def && def.values) {\n            // If it's a property with an array of values\n            // skip to the next one looping back if at end.\n            this[property] = arrayNext(def.values, this[property]);\n        } else {\n            throw new TypeError('Can only toggle properties that are type `boolean` or have `values` array.');\n        }\n        return this;\n    },\n\n    // Get all of the attributes of the model at the time of the previous\n    // `\"change\"` event.\n    previousAttributes: function () {\n        return cloneObj(this._previousAttributes);\n    },\n\n    // Determine if the model has changed since the last `\"change\"` event.\n    // If you specify an attribute name, determine if that attribute has changed.\n    hasChanged: function (attr) {\n        if (attr == null) return !!Object.keys(this._changed).length;\n        if (has(this._derived, attr)) {\n            return this._derived[attr].depList.some(function (dep) {\n                return this.hasChanged(dep);\n            }, this);\n        }\n        return has(this._changed, attr);\n    },\n\n    // Return an object containing all the attributes that have changed, or\n    // false if there are no changed attributes. Useful for determining what\n    // parts of a view need to be updated and/or what attributes need to be\n    // persisted to the server. Unset attributes will be set to undefined.\n    // You can also pass an attributes object to diff against the model,\n    // determining if there *would be* a change.\n    changedAttributes: function (diff) {\n        if (!diff) return this.hasChanged() ? cloneObj(this._changed) : false;\n        var val, changed = false;\n        var old = this._changing ? this._previousAttributes : this.attributes;\n        var def, isEqual;\n        for (var attr in diff) {\n            def = this._definition[attr];\n            if (!def) continue;\n            isEqual = this._getCompareForType(def.type);\n            if (isEqual(old[attr], (val = diff[attr]))) continue;\n            (changed || (changed = {}))[attr] = val;\n        }\n        return changed;\n    },\n\n    toJSON: function () {\n        return this.serialize();\n    },\n\n    unset: function (attrs, options) {\n        var self = this;\n        attrs = Array.isArray(attrs) ? attrs : [attrs];\n        attrs.forEach(function (key) {\n            var def = self._definition[key];\n            if (!def) return;\n            var val;\n            if (def.required) {\n                val = result(def, 'default');\n                return self.set(key, val, options);\n            } else {\n                return self.set(key, val, assign({}, options, {unset: true}));\n            }\n        });\n    },\n\n    clear: function (options) {\n        var self = this;\n        Object.keys(this.attributes).forEach(function (key) {\n            self.unset(key, options);\n        });\n        return this;\n    },\n\n    previous: function (attr) {\n        if (attr == null || !Object.keys(this._previousAttributes).length) return null;\n        return this._previousAttributes[attr];\n    },\n\n    // Get default values for a certain type\n    _getDefaultForType: function (type) {\n        var dataType = this._dataTypes[type];\n        return dataType && dataType['default'];\n    },\n\n    // Determine which comparison algorithm to use for comparing a property\n    _getCompareForType: function (type) {\n        var dataType = this._dataTypes[type];\n        if (dataType && dataType.compare) return dataType.compare.bind(this);\n        return _isEqual; // if no compare function is defined, use _.isEqual\n    },\n\n    _getOnChangeForType : function(type){\n        var dataType = this._dataTypes[type];\n        if (dataType && dataType.onChange) return dataType.onChange.bind(this);\n        return noop;\n    },\n\n    // Run validation against the next complete set of model attributes,\n    // returning `true` if all is well. Otherwise, fire an `\"invalid\"` event.\n    _validate: function (attrs, options) {\n        if (!options.validate || !this.validate) return true;\n        attrs = assign({}, this.attributes, attrs);\n        var error = this.validationError = this.validate(attrs, options) || null;\n        if (!error) return true;\n        this.trigger('invalid', this, error, assign(options || {}, {validationError: error}));\n        return false;\n    },\n\n    _createPropertyDefinition: function (name, desc, isSession) {\n        return createPropertyDefinition(this, name, desc, isSession);\n    },\n\n    // just makes friendlier errors when trying to define a new model\n    // only used when setting up original property definitions\n    _ensureValidType: function (type) {\n        return includes(['string', 'number', 'boolean', 'array', 'object', 'date', 'state', 'any']\n            .concat(Object.keys(this._dataTypes)), type) ? type : undefined;\n    },\n\n    getAttributes: function (options, raw) {\n        options = assign({\n            session: false,\n            props: false,\n            derived: false\n        }, options || {});\n        var res = {};\n        var val, def;\n        for (var item in this._definition) {\n            def = this._definition[item];\n            if ((options.session && def.session) || (options.props && !def.session)) {\n                val = raw ? this._values[item] : this[item];\n                if (raw && val && isFunction(val.serialize)) val = val.serialize();\n                if (typeof val === 'undefined') val = result(def, 'default');\n                if (typeof val !== 'undefined') res[item] = val;\n            }\n        }\n        if (options.derived) {\n            for (var derivedItem in this._derived) res[derivedItem] = this[derivedItem];\n        }\n        return res;\n    },\n\n    _initDerived: function () {\n        var self = this;\n\n        forOwn(this._derived, function (value, name) {\n            var def = self._derived[name];\n            def.deps = def.depList;\n\n            var update = function () {\n                var newVal = def.fn.call(self);\n\n                if (self._cache[name] !== newVal || !def.cache) {\n                    if (def.cache) {\n                        self._previousAttributes[name] = self._cache[name];\n                    }\n                    self._cache[name] = newVal;\n                    self.trigger('change:' + name, self, self._cache[name]);\n                }\n            };\n\n            def.deps.forEach(function (propString) {\n                self._keyTree.add(propString, update);\n            });\n        });\n\n        this.on('all', function (eventName) {\n            if (changeRE.test(eventName)) {\n                self._keyTree.get(eventName.split(':')[1]).forEach(function (fn) {\n                    fn();\n                });\n            }\n        }, this);\n    },\n\n    _getDerivedProperty: function (name, flushCache) {\n        // is this a derived property that is cached\n        if (this._derived[name].cache) {\n            //set if this is the first time, or flushCache is set\n            if (flushCache || !this._cache.hasOwnProperty(name)) {\n                this._cache[name] = this._derived[name].fn.apply(this);\n            }\n            return this._cache[name];\n        } else {\n            return this._derived[name].fn.apply(this);\n        }\n    },\n\n    _initCollections: function () {\n        var coll;\n        if (!this._collections) return;\n        for (coll in this._collections) {\n            this._safeSet(coll, new this._collections[coll](null, {parent: this}));\n        }\n    },\n\n    _initChildren: function () {\n        var child;\n        if (!this._children) return;\n        for (child in this._children) {\n            this._safeSet(child, new this._children[child]({}, {parent: this}));\n            this.listenTo(this[child], 'all', this._getCachedEventBubblingHandler(child));\n        }\n    },\n\n    // Returns a bound handler for doing event bubbling while\n    // adding a name to the change string.\n    _getCachedEventBubblingHandler: function (propertyName) {\n        if (!this._eventBubblingHandlerCache[propertyName]) {\n            this._eventBubblingHandlerCache[propertyName] = function (name, model, newValue) {\n                if (changeRE.test(name)) {\n                    this.trigger('change:' + propertyName + '.' + name.split(':')[1], model, newValue);\n                } else if (name === 'change') {\n                    this.trigger('change', this);\n                }\n            }.bind(this);\n        }\n        return this._eventBubblingHandlerCache[propertyName];\n    },\n\n    // Check that all required attributes are present\n    _verifyRequired: function () {\n        var attrs = this.attributes; // should include session\n        for (var def in this._definition) {\n            if (this._definition[def].required && typeof attrs[def] === 'undefined') {\n                return false;\n            }\n        }\n        return true;\n    },\n\n    // expose safeSet method\n    _safeSet: function safeSet(property, value) {\n        if (property in this) {\n            throw new Error('Encountered namespace collision while setting instance property `' + property + '`');\n        }\n        this[property] = value;\n        return this;\n    }\n});\n\n// getter for attributes\nObject.defineProperties(Base.prototype, {\n    attributes: {\n        get: function () {\n            return this.getAttributes({props: true, session: true});\n        }\n    },\n    all: {\n        get: function () {\n            return this.getAttributes({\n                session: true,\n                props: true,\n                derived: true\n            });\n        }\n    },\n    isState: {\n        get: function () { return true; },\n        set: function () { }\n    }\n});\n\n// helper for creating/storing property definitions and creating\n// appropriate getters/setters\nfunction createPropertyDefinition(object, name, desc, isSession) {\n    var def = object._definition[name] = {};\n    var type, descArray;\n\n    if (isString(desc)) {\n        // grab our type if all we've got is a string\n        type = object._ensureValidType(desc);\n        if (type) def.type = type;\n    } else {\n        //Transform array of ['type', required, default] to object form\n        if (Array.isArray(desc)) {\n            descArray = desc;\n            desc = {\n                type: descArray[0],\n                required: descArray[1],\n                'default': descArray[2]\n            };\n        }\n\n        type = object._ensureValidType(desc.type);\n        if (type) def.type = type;\n\n        if (desc.required) def.required = true;\n\n        if (desc['default'] && typeof desc['default'] === 'object') {\n            throw new TypeError('The default value for ' + name + ' cannot be an object/array, must be a value or a function which returns a value/object/array');\n        }\n\n        def['default'] = desc['default'];\n\n        def.allowNull = desc.allowNull ? desc.allowNull : false;\n        if (desc.setOnce) def.setOnce = true;\n        if (def.required && def['default'] === undefined && !def.setOnce) def['default'] = object._getDefaultForType(type);\n        def.test = desc.test;\n        def.values = desc.values;\n    }\n    if (isSession) def.session = true;\n\n    if (!type) {\n        type = isString(desc) ? desc : desc.type;\n        // TODO: start throwing a TypeError in future major versions instead of warning\n        console.warn('Invalid data type of `' + type + '` for `' + name + '` property. Use one of the default types or define your own');\n    }\n\n    // define a getter/setter on the prototype\n    // but they get/set on the instance\n    Object.defineProperty(object, name, {\n        set: function (val) {\n            this.set(name, val);\n        },\n        get: function () {\n            if (!this._values) {\n                throw Error('You may be trying to `extend` a state object with \"' + name + '\" which has been defined in `props` on the object being extended');\n            }\n            var value = this._values[name];\n            var typeDef = this._dataTypes[def.type];\n            if (typeof value !== 'undefined') {\n                if (typeDef && typeDef.get) {\n                    value = typeDef.get(value);\n                }\n                return value;\n            }\n            var defaultValue = result(def, 'default');\n            this._values[name] = defaultValue;\n            // If we've set a defaultValue, fire a change handler effectively marking\n            // its change from undefined to the default value.\n            if (typeof defaultValue !== 'undefined') {\n                var onChange = this._getOnChangeForType(def.type);\n                onChange(defaultValue, value, name);\n            }\n            return defaultValue;\n        }\n    });\n\n    return def;\n}\n\n// helper for creating derived property definitions\nfunction createDerivedProperty(modelProto, name, definition) {\n    var def = modelProto._derived[name] = {\n        fn: isFunction(definition) ? definition : definition.fn,\n        cache: (definition.cache !== false),\n        depList: definition.deps || []\n    };\n\n    // add to our shared dependency list\n    def.depList.forEach(function (dep) {\n        modelProto._deps[dep] = union(modelProto._deps[dep] || [], [name]);\n    });\n\n    // defined a top-level getter for derived names\n    Object.defineProperty(modelProto, name, {\n        get: function () {\n            return this._getDerivedProperty(name);\n        },\n        set: function () {\n            throw new TypeError(\"`\" + name + \"` is a derived property, it can't be set directly.\");\n        }\n    });\n}\n\nvar dataTypes = {\n    string: {\n        'default': function () {\n            return '';\n        }\n    },\n    date: {\n        set: function (newVal) {\n            var newType;\n            if (newVal == null) {\n                newType = typeof null;\n            } else if (!isDate(newVal)) {\n                var err = null;\n                var dateVal = new Date(newVal).valueOf();\n                if (isNaN(dateVal)) {\n                    // If the newVal cant be parsed, then try parseInt first\n                    dateVal = new Date(parseInt(newVal, 10)).valueOf();\n                    if (isNaN(dateVal)) err = true;\n                }\n                newVal = dateVal;\n                newType = 'date';\n                if (err) {\n                    newType = typeof newVal;\n                }\n            } else {\n                newType = 'date';\n                newVal = newVal.valueOf();\n            }\n\n            return {\n                val: newVal,\n                type: newType\n            };\n        },\n        get: function (val) {\n            if (val == null) { return val; }\n            return new Date(val);\n        },\n        'default': function () {\n            return new Date();\n        }\n    },\n    array: {\n        set: function (newVal) {\n            return {\n                val: newVal,\n                type: Array.isArray(newVal) ? 'array' : typeof newVal\n            };\n        },\n        'default': function () {\n            return [];\n        }\n    },\n    object: {\n        set: function (newVal) {\n            var newType = typeof newVal;\n            // we have to have a way of supporting \"missing\" objects.\n            // Null is an object, but setting a value to undefined\n            // should work too, IMO. We just override it, in that case.\n            if (newType !== 'object' && newVal === undefined) {\n                newVal = null;\n                newType = 'object';\n            }\n            return {\n                val: newVal,\n                type: newType\n            };\n        },\n        'default': function () {\n            return {};\n        }\n    },\n    // the `state` data type is a bit special in that setting it should\n    // also bubble events\n    state: {\n        set: function (newVal) {\n            var isInstance = newVal instanceof Base || (newVal && newVal.isState);\n            if (isInstance) {\n                return {\n                    val: newVal,\n                    type: 'state'\n                };\n            } else {\n                return {\n                    val: newVal,\n                    type: typeof newVal\n                };\n            }\n        },\n        compare: function (currentVal, newVal) {\n            return currentVal === newVal;\n        },\n\n        onChange : function(newVal, previousVal, attributeName){\n            // if this has changed we want to also handle\n            // event propagation\n            if (previousVal) {\n                this.stopListening(previousVal, 'all', this._getCachedEventBubblingHandler(attributeName));\n            }\n\n            if (newVal != null) {\n                this.listenTo(newVal, 'all', this._getCachedEventBubblingHandler(attributeName));\n            }\n        }\n    }\n};\n\n// the extend method used to extend prototypes, maintain inheritance chains for instanceof\n// and allow for additions to the model definitions.\nfunction extend(protoProps) {\n    /*jshint validthis:true*/\n    var parent = this;\n    var child;\n\n    // The constructor function for the new subclass is either defined by you\n    // (the \"constructor\" property in your `extend` definition), or defaulted\n    // by us to simply call the parent's constructor.\n    if (protoProps && protoProps.hasOwnProperty('constructor')) {\n        child = protoProps.constructor;\n    } else {\n        child = function () {\n            return parent.apply(this, arguments);\n        };\n    }\n\n    // Add static properties to the constructor function from parent\n    assign(child, parent);\n\n    // Set the prototype chain to inherit from `parent`, without calling\n    // `parent`'s constructor function.\n    var Surrogate = function () { this.constructor = child; };\n    Surrogate.prototype = parent.prototype;\n    child.prototype = new Surrogate();\n\n    // set prototype level objects\n    child.prototype._derived =  assign({}, parent.prototype._derived);\n    child.prototype._deps = assign({}, parent.prototype._deps);\n    child.prototype._definition = assign({}, parent.prototype._definition);\n    child.prototype._collections = assign({}, parent.prototype._collections);\n    child.prototype._children = assign({}, parent.prototype._children);\n    child.prototype._dataTypes = assign({}, parent.prototype._dataTypes || dataTypes);\n\n    // Mix in all prototype properties to the subclass if supplied.\n    if (protoProps) {\n        var omitFromExtend = [\n            'dataTypes', 'props', 'session', 'derived', 'collections', 'children'\n        ];\n        for(var i = 0; i < arguments.length; i++) {\n            var def = arguments[i];\n            if (def.dataTypes) {\n                forOwn(def.dataTypes, function (def, name) {\n                    child.prototype._dataTypes[name] = def;\n                });\n            }\n            if (def.props) {\n                forOwn(def.props, function (def, name) {\n                    createPropertyDefinition(child.prototype, name, def);\n                });\n            }\n            if (def.session) {\n                forOwn(def.session, function (def, name) {\n                    createPropertyDefinition(child.prototype, name, def, true);\n                });\n            }\n            if (def.derived) {\n                forOwn(def.derived, function (def, name) {\n                    createDerivedProperty(child.prototype, name, def);\n                });\n            }\n            if (def.collections) {\n                forOwn(def.collections, function (constructor, name) {\n                    child.prototype._collections[name] = constructor;\n                });\n            }\n            if (def.children) {\n                forOwn(def.children, function (constructor, name) {\n                    child.prototype._children[name] = constructor;\n                });\n            }\n            assign(child.prototype, omit(def, omitFromExtend));\n        }\n    }\n\n    // Set a convenience property in case the parent's prototype is needed\n    // later.\n    child.__super__ = parent.prototype;\n\n    return child;\n}\n\nBase.extend = extend;\n\n// Our main exports\nmodule.exports = Base;\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWY0NS5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9hbXBlcnNhbmQtc3RhdGUvYW1wZXJzYW5kLXN0YXRlLmpzPzYzZDQiXSwic291cmNlc0NvbnRlbnQiOlsiJ3VzZSBzdHJpY3QnO1xuLyokQU1QRVJTQU5EX1ZFUlNJT04qL1xudmFyIHVuaXF1ZUlkID0gcmVxdWlyZSgnbG9kYXNoL3VuaXF1ZUlkJyk7XG52YXIgYXNzaWduID0gcmVxdWlyZSgnbG9kYXNoL2Fzc2lnbicpO1xudmFyIGNsb25lT2JqID0gZnVuY3Rpb24ob2JqKSB7IHJldHVybiBhc3NpZ24oe30sIG9iaik7IH07XG52YXIgb21pdCA9IHJlcXVpcmUoJ2xvZGFzaC9vbWl0Jyk7XG52YXIgZXNjYXBlID0gcmVxdWlyZSgnbG9kYXNoL2VzY2FwZScpO1xudmFyIGZvck93biA9IHJlcXVpcmUoJ2xvZGFzaC9mb3JPd24nKTtcbnZhciBpbmNsdWRlcyA9IHJlcXVpcmUoJ2xvZGFzaC9pbmNsdWRlcycpO1xudmFyIGlzU3RyaW5nID0gcmVxdWlyZSgnbG9kYXNoL2lzU3RyaW5nJyk7XG52YXIgaXNPYmplY3QgPSByZXF1aXJlKCdsb2Rhc2gvaXNPYmplY3QnKTtcbnZhciBpc0RhdGUgPSByZXF1aXJlKCdsb2Rhc2gvaXNEYXRlJyk7XG52YXIgaXNGdW5jdGlvbiA9IHJlcXVpcmUoJ2xvZGFzaC9pc0Z1bmN0aW9uJyk7XG52YXIgX2lzRXF1YWwgPSByZXF1aXJlKCdsb2Rhc2gvaXNFcXVhbCcpOyAvLyB0byBhdm9pZCBzaGFkb3dpbmdcbnZhciBoYXMgPSByZXF1aXJlKCdsb2Rhc2gvaGFzJyk7XG52YXIgcmVzdWx0ID0gcmVxdWlyZSgnbG9kYXNoL3Jlc3VsdCcpO1xudmFyIHVuaW9uID0gcmVxdWlyZSgnbG9kYXNoL3VuaW9uJyk7XG52YXIgRXZlbnRzID0gcmVxdWlyZSgnYW1wZXJzYW5kLWV2ZW50cycpO1xudmFyIEtleVRyZWUgPSByZXF1aXJlKCdrZXktdHJlZS1zdG9yZScpO1xudmFyIGFycmF5TmV4dCA9IHJlcXVpcmUoJ2FycmF5LW5leHQnKTtcbnZhciBjaGFuZ2VSRSA9IC9eY2hhbmdlOi87XG52YXIgbm9vcCA9IGZ1bmN0aW9uICgpIHt9O1xuXG5mdW5jdGlvbiBCYXNlKGF0dHJzLCBvcHRpb25zKSB7XG4gICAgb3B0aW9ucyB8fCAob3B0aW9ucyA9IHt9KTtcbiAgICB0aGlzLmNpZCB8fCAodGhpcy5jaWQgPSB1bmlxdWVJZCgnc3RhdGUnKSk7XG4gICAgdGhpcy5fZXZlbnRzID0ge307XG4gICAgdGhpcy5fdmFsdWVzID0ge307XG4gICAgdGhpcy5fZXZlbnRCdWJibGluZ0hhbmRsZXJDYWNoZSA9IHt9O1xuICAgIHRoaXMuX2RlZmluaXRpb24gPSBPYmplY3QuY3JlYXRlKHRoaXMuX2RlZmluaXRpb24pO1xuICAgIGlmIChvcHRpb25zLnBhcnNlKSBhdHRycyA9IHRoaXMucGFyc2UoYXR0cnMsIG9wdGlvbnMpO1xuICAgIHRoaXMucGFyZW50ID0gb3B0aW9ucy5wYXJlbnQ7XG4gICAgdGhpcy5jb2xsZWN0aW9uID0gb3B0aW9ucy5jb2xsZWN0aW9uO1xuICAgIHRoaXMuX2tleVRyZWUgPSBuZXcgS2V5VHJlZSgpO1xuICAgIHRoaXMuX2luaXRDb2xsZWN0aW9ucygpO1xuICAgIHRoaXMuX2luaXRDaGlsZHJlbigpO1xuICAgIHRoaXMuX2NhY2hlID0ge307XG4gICAgdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzID0ge307XG4gICAgaWYgKGF0dHJzKSB0aGlzLnNldChhdHRycywgYXNzaWduKHtzaWxlbnQ6IHRydWUsIGluaXRpYWw6IHRydWV9LCBvcHRpb25zKSk7XG4gICAgdGhpcy5fY2hhbmdlZCA9IHt9O1xuICAgIGlmICh0aGlzLl9kZXJpdmVkKSB0aGlzLl9pbml0RGVyaXZlZCgpO1xuICAgIGlmIChvcHRpb25zLmluaXQgIT09IGZhbHNlKSB0aGlzLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cblxuYXNzaWduKEJhc2UucHJvdG90eXBlLCBFdmVudHMsIHtcbiAgICAvLyBjYW4gYmUgYWxsb3csIGlnbm9yZSwgcmVqZWN0XG4gICAgZXh0cmFQcm9wZXJ0aWVzOiAnaWdub3JlJyxcblxuICAgIGlkQXR0cmlidXRlOiAnaWQnLFxuXG4gICAgbmFtZXNwYWNlQXR0cmlidXRlOiAnbmFtZXNwYWNlJyxcblxuICAgIHR5cGVBdHRyaWJ1dGU6ICdtb2RlbFR5cGUnLFxuXG4gICAgLy8gU3R1YmJlZCBvdXQgdG8gYmUgb3ZlcndyaXR0ZW5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICAvLyBHZXQgSUQgb2YgbW9kZWwgcGVyIGNvbmZpZ3VyYXRpb24uXG4gICAgLy8gU2hvdWxkICphbHdheXMqIGJlIGhvdyBJRCBpcyBkZXRlcm1pbmVkIGJ5IG90aGVyIGNvZGUuXG4gICAgZ2V0SWQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXNbdGhpcy5pZEF0dHJpYnV0ZV07XG4gICAgfSxcblxuICAgIC8vIEdldCBuYW1lc3BhY2Ugb2YgbW9kZWwgcGVyIGNvbmZpZ3VyYXRpb24uXG4gICAgLy8gU2hvdWxkICphbHdheXMqIGJlIGhvdyBuYW1lc3BhY2UgaXMgZGV0ZXJtaW5lZCBieSBvdGhlciBjb2RlLlxuICAgIGdldE5hbWVzcGFjZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpc1t0aGlzLm5hbWVzcGFjZUF0dHJpYnV0ZV07XG4gICAgfSxcblxuICAgIC8vIEdldCB0eXBlIG9mIG1vZGVsIHBlciBjb25maWd1cmF0aW9uLlxuICAgIC8vIFNob3VsZCAqYWx3YXlzKiBiZSBob3cgdHlwZSBpcyBkZXRlcm1pbmVkIGJ5IG90aGVyIGNvZGUuXG4gICAgZ2V0VHlwZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpc1t0aGlzLnR5cGVBdHRyaWJ1dGVdO1xuICAgIH0sXG5cbiAgICAvLyBBIG1vZGVsIGlzIG5ldyBpZiBpdCBoYXMgbmV2ZXIgYmVlbiBzYXZlZCB0byB0aGUgc2VydmVyLCBhbmQgbGFja3MgYW4gaWQuXG4gICAgaXNOZXc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0SWQoKSA9PSBudWxsO1xuICAgIH0sXG5cbiAgICAvLyBnZXQgSFRNTC1lc2NhcGVkIHZhbHVlIG9mIGF0dHJpYnV0ZVxuICAgIGVzY2FwZTogZnVuY3Rpb24gKGF0dHIpIHtcbiAgICAgICAgcmV0dXJuIGVzY2FwZSh0aGlzLmdldChhdHRyKSk7XG4gICAgfSxcblxuICAgIC8vIENoZWNrIGlmIHRoZSBtb2RlbCBpcyBjdXJyZW50bHkgaW4gYSB2YWxpZCBzdGF0ZS5cbiAgICBpc1ZhbGlkOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5fdmFsaWRhdGUoe30sIGFzc2lnbihvcHRpb25zIHx8IHt9LCB7IHZhbGlkYXRlOiB0cnVlIH0pKTtcbiAgICB9LFxuXG4gICAgLy8gUGFyc2UgY2FuIGJlIHVzZWQgcmVtYXAvcmVzdHJ1Y3R1cmUvcmVuYW1lIGluY29taW5nIHByb3BlcnRpZXNcbiAgICAvLyBiZWZvcmUgdGhleSBhcmUgYXBwbGllZCB0byBhdHRyaWJ1dGVzLlxuICAgIHBhcnNlOiBmdW5jdGlvbiAocmVzcCwgb3B0aW9ucykge1xuICAgICAgICAvL2pzaGludCB1bnVzZWQ6ZmFsc2VcbiAgICAgICAgcmV0dXJuIHJlc3A7XG4gICAgfSxcblxuICAgIC8vIFNlcmlhbGl6ZSBpcyB0aGUgaW52ZXJzZSBvZiBgcGFyc2VgIGl0IGxldHMgeW91IG1hc3NhZ2UgZGF0YVxuICAgIC8vIG9uIHRoZSB3YXkgb3V0LiBCZWZvcmUsIHNlbmRpbmcgdG8gc2VydmVyLCBmb3IgZXhhbXBsZS5cbiAgICBzZXJpYWxpemU6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBhdHRyT3B0cyA9IGFzc2lnbih7cHJvcHM6IHRydWV9LCBvcHRpb25zKTtcbiAgICAgICAgdmFyIHJlcyA9IHRoaXMuZ2V0QXR0cmlidXRlcyhhdHRyT3B0cywgdHJ1ZSk7XG4gICAgICAgIFxuICAgICAgICB2YXIgc2V0RnJvbVNlcmlhbGl6ZWRWYWx1ZSA9IGZ1bmN0aW9uICh2YWx1ZSwga2V5KSB7XG5cdCAgICAgICAgcmVzW2tleV0gPSB0aGlzW2tleV0uc2VyaWFsaXplKCk7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcbiAgICAgICAgXG4gICAgICAgIGZvck93bih0aGlzLl9jaGlsZHJlbiwgc2V0RnJvbVNlcmlhbGl6ZWRWYWx1ZSk7XG4gICAgICAgIGZvck93bih0aGlzLl9jb2xsZWN0aW9ucywgc2V0RnJvbVNlcmlhbGl6ZWRWYWx1ZSk7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfSxcblxuICAgIC8vIE1haW4gc2V0IG1ldGhvZCB1c2VkIGJ5IGdlbmVyYXRlZCBzZXR0ZXJzL2dldHRlcnMgYW5kIGNhblxuICAgIC8vIGJlIHVzZWQgZGlyZWN0bHkgaWYgeW91IG5lZWQgdG8gcGFzcyBvcHRpb25zIG9yIHNldCBtdWx0aXBsZVxuICAgIC8vIHByb3BlcnRpZXMgYXQgb25jZS5cbiAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgdmFyIGV4dHJhUHJvcGVydGllcyA9IHRoaXMuZXh0cmFQcm9wZXJ0aWVzO1xuICAgICAgICB2YXIgd2FzQ2hhbmdpbmcsIGNoYW5nZUV2ZW50cywgbmV3VHlwZSwgbmV3VmFsLCBkZWYsIGNhc3QsIGVyciwgYXR0cixcbiAgICAgICAgICAgIGF0dHJzLCBkYXRhVHlwZSwgc2lsZW50LCB1bnNldCwgY3VycmVudFZhbCwgaW5pdGlhbCwgaGFzQ2hhbmdlZCwgaXNFcXVhbCwgb25DaGFuZ2U7XG5cbiAgICAgICAgLy8gSGFuZGxlIGJvdGggYFwia2V5XCIsIHZhbHVlYCBhbmQgYHtrZXk6IHZhbHVlfWAgLXN0eWxlIGFyZ3VtZW50cy5cbiAgICAgICAgaWYgKGlzT2JqZWN0KGtleSkgfHwga2V5ID09PSBudWxsKSB7XG4gICAgICAgICAgICBhdHRycyA9IGtleTtcbiAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGF0dHJzID0ge307XG4gICAgICAgICAgICBhdHRyc1trZXldID0gdmFsdWU7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICBpZiAoIXRoaXMuX3ZhbGlkYXRlKGF0dHJzLCBvcHRpb25zKSkgcmV0dXJuIGZhbHNlO1xuXG4gICAgICAgIC8vIEV4dHJhY3QgYXR0cmlidXRlcyBhbmQgb3B0aW9ucy5cbiAgICAgICAgdW5zZXQgPSBvcHRpb25zLnVuc2V0O1xuICAgICAgICBzaWxlbnQgPSBvcHRpb25zLnNpbGVudDtcbiAgICAgICAgaW5pdGlhbCA9IG9wdGlvbnMuaW5pdGlhbDtcblxuICAgICAgICAvLyBJbml0aWFsaXplIGNoYW5nZSB0cmFja2luZy5cbiAgICAgICAgd2FzQ2hhbmdpbmcgPSB0aGlzLl9jaGFuZ2luZztcbiAgICAgICAgdGhpcy5fY2hhbmdpbmcgPSB0cnVlO1xuICAgICAgICBjaGFuZ2VFdmVudHMgPSBbXTtcblxuICAgICAgICAvLyBpZiBub3QgYWxyZWFkeSBjaGFuZ2luZywgc3RvcmUgcHJldmlvdXNcbiAgICAgICAgaWYgKGluaXRpYWwpIHtcbiAgICAgICAgICAgIHRoaXMuX3ByZXZpb3VzQXR0cmlidXRlcyA9IHt9O1xuICAgICAgICB9IGVsc2UgaWYgKCF3YXNDaGFuZ2luZykge1xuICAgICAgICAgICAgdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzID0gdGhpcy5hdHRyaWJ1dGVzO1xuICAgICAgICAgICAgdGhpcy5fY2hhbmdlZCA9IHt9O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRm9yIGVhY2ggYHNldGAgYXR0cmlidXRlLi4uXG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBrZXlzID0gT2JqZWN0LmtleXMoYXR0cnMpLCBsZW4gPSBrZXlzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgICAgICBhdHRyID0ga2V5c1tpXTtcbiAgICAgICAgICAgIG5ld1ZhbCA9IGF0dHJzW2F0dHJdO1xuICAgICAgICAgICAgbmV3VHlwZSA9IHR5cGVvZiBuZXdWYWw7XG4gICAgICAgICAgICBjdXJyZW50VmFsID0gdGhpcy5fdmFsdWVzW2F0dHJdO1xuICAgICAgICAgICAgZGVmID0gdGhpcy5fZGVmaW5pdGlvblthdHRyXTtcblxuICAgICAgICAgICAgaWYgKCFkZWYpIHtcbiAgICAgICAgICAgICAgICAvLyBpZiB0aGlzIGlzIGEgY2hpbGQgbW9kZWwgb3IgY29sbGVjdGlvblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLl9jaGlsZHJlblthdHRyXSB8fCB0aGlzLl9jb2xsZWN0aW9uc1thdHRyXSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWlzT2JqZWN0KG5ld1ZhbCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5ld1ZhbCA9IHt9O1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpc1thdHRyXS5zZXQobmV3VmFsLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChleHRyYVByb3BlcnRpZXMgPT09ICdpZ25vcmUnKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoZXh0cmFQcm9wZXJ0aWVzID09PSAncmVqZWN0Jykge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdObyBcIicgKyBhdHRyICsgJ1wiIHByb3BlcnR5IGRlZmluZWQgb24gJyArICh0aGlzLnR5cGUgfHwgJ3RoaXMnKSArICcgbW9kZWwgYW5kIGV4dHJhUHJvcGVydGllcyBub3Qgc2V0IHRvIFwiaWdub3JlXCIgb3IgXCJhbGxvd1wiJyk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChleHRyYVByb3BlcnRpZXMgPT09ICdhbGxvdycpIHtcbiAgICAgICAgICAgICAgICAgICAgZGVmID0gdGhpcy5fY3JlYXRlUHJvcGVydHlEZWZpbml0aW9uKGF0dHIsICdhbnknKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGV4dHJhUHJvcGVydGllcykge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdJbnZhbGlkIHZhbHVlIGZvciBleHRyYVByb3BlcnRpZXM6IFwiJyArIGV4dHJhUHJvcGVydGllcyArICdcIicpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaXNFcXVhbCA9IHRoaXMuX2dldENvbXBhcmVGb3JUeXBlKGRlZi50eXBlKTtcbiAgICAgICAgICAgIG9uQ2hhbmdlID0gdGhpcy5fZ2V0T25DaGFuZ2VGb3JUeXBlKGRlZi50eXBlKTtcbiAgICAgICAgICAgIGRhdGFUeXBlID0gdGhpcy5fZGF0YVR5cGVzW2RlZi50eXBlXTtcblxuICAgICAgICAgICAgLy8gY2hlY2sgdHlwZSBpZiB3ZSBoYXZlIG9uZVxuICAgICAgICAgICAgaWYgKGRhdGFUeXBlICYmIGRhdGFUeXBlLnNldCkge1xuICAgICAgICAgICAgICAgIGNhc3QgPSBkYXRhVHlwZS5zZXQobmV3VmFsKTtcbiAgICAgICAgICAgICAgICBuZXdWYWwgPSBjYXN0LnZhbDtcbiAgICAgICAgICAgICAgICBuZXdUeXBlID0gY2FzdC50eXBlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBJZiB3ZSd2ZSBkZWZpbmVkIGEgdGVzdCwgcnVuIGl0XG4gICAgICAgICAgICBpZiAoZGVmLnRlc3QpIHtcbiAgICAgICAgICAgICAgICBlcnIgPSBkZWYudGVzdC5jYWxsKHRoaXMsIG5ld1ZhbCwgbmV3VHlwZSk7XG4gICAgICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdQcm9wZXJ0eSBcXCcnICsgYXR0ciArICdcXCcgZmFpbGVkIHZhbGlkYXRpb24gd2l0aCBlcnJvcjogJyArIGVycik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBJZiB3ZSBhcmUgcmVxdWlyZWQgYnV0IHVuZGVmaW5lZCwgdGhyb3cgZXJyb3IuXG4gICAgICAgICAgICAvLyBJZiB3ZSBhcmUgbnVsbCBhbmQgYXJlIG5vdCBhbGxvd2luZyBudWxsLCB0aHJvdyBlcnJvclxuICAgICAgICAgICAgLy8gSWYgd2UgaGF2ZSBhIGRlZmluZWQgdHlwZSBhbmQgdGhlIG5ldyB0eXBlIGRvZXNuJ3QgbWF0Y2gsIGFuZCB3ZSBhcmUgbm90IG51bGwsIHRocm93IGVycm9yLlxuICAgICAgICAgICAgLy8gSWYgd2UgcmVxdWlyZSBzcGVjaWZpYyB2YWx1ZSBhbmQgbmV3IG9uZSBpcyBub3Qgb25lIG9mIHRoZW0sIHRocm93IGVycm9yICh1bmxlc3MgaXQgaGFzIGRlZmF1bHQgdmFsdWUgb3Igd2UncmUgdW5zZXR0aW5nIGl0IHdpdGggdW5kZWZpbmVkKS5cblxuICAgICAgICAgICAgaWYgKG5ld1ZhbCA9PT0gdW5kZWZpbmVkICYmIGRlZi5yZXF1aXJlZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1JlcXVpcmVkIHByb3BlcnR5IFxcJycgKyBhdHRyICsgJ1xcJyBtdXN0IGJlIG9mIHR5cGUgJyArIGRlZi50eXBlICsgJy4gVHJpZWQgdG8gc2V0ICcgKyBuZXdWYWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG5ld1ZhbCA9PT0gbnVsbCAmJiBkZWYucmVxdWlyZWQgJiYgIWRlZi5hbGxvd051bGwpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdQcm9wZXJ0eSBcXCcnICsgYXR0ciArICdcXCcgbXVzdCBiZSBvZiB0eXBlICcgKyBkZWYudHlwZSArICcgKGNhbm5vdCBiZSBudWxsKS4gVHJpZWQgdG8gc2V0ICcgKyBuZXdWYWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKChkZWYudHlwZSAmJiBkZWYudHlwZSAhPT0gJ2FueScgJiYgZGVmLnR5cGUgIT09IG5ld1R5cGUpICYmIG5ld1ZhbCAhPT0gbnVsbCAmJiBuZXdWYWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Byb3BlcnR5IFxcJycgKyBhdHRyICsgJ1xcJyBtdXN0IGJlIG9mIHR5cGUgJyArIGRlZi50eXBlICsgJy4gVHJpZWQgdG8gc2V0ICcgKyBuZXdWYWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRlZi52YWx1ZXMgJiYgIWluY2x1ZGVzKGRlZi52YWx1ZXMsIG5ld1ZhbCkpIHtcbiAgICAgICAgICAgICAgICB2YXIgZGVmYXVsdFZhbHVlID0gcmVzdWx0KGRlZiwgJ2RlZmF1bHQnKTtcbiAgICAgICAgICAgICAgICBpZiAodW5zZXQgJiYgZGVmYXVsdFZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgbmV3VmFsID0gZGVmYXVsdFZhbHVlO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoIXVuc2V0IHx8ICh1bnNldCAmJiBuZXdWYWwgIT09IHVuZGVmaW5lZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignUHJvcGVydHkgXFwnJyArIGF0dHIgKyAnXFwnIG11c3QgYmUgb25lIG9mIHZhbHVlczogJyArIGRlZi52YWx1ZXMuam9pbignLCAnKSArICcuIFRyaWVkIHRvIHNldCAnICsgbmV3VmFsKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFdlIGtub3cgdGhpcyBoYXMgJ2NoYW5nZWQnIGlmIGl0J3MgdGhlIGluaXRpYWwgc2V0LCBzbyBza2lwIGEgcG90ZW50aWFsbHkgZXhwZW5zaXZlIGlzRXF1YWwgY2hlY2suXG4gICAgICAgICAgICBoYXNDaGFuZ2VkID0gaW5pdGlhbCB8fCAhaXNFcXVhbChjdXJyZW50VmFsLCBuZXdWYWwsIGF0dHIpO1xuXG4gICAgICAgICAgICAvLyBlbmZvcmNlIGBzZXRPbmNlYCBmb3IgcHJvcGVydGllcyBpZiBzZXRcbiAgICAgICAgICAgIGlmIChkZWYuc2V0T25jZSAmJiBjdXJyZW50VmFsICE9PSB1bmRlZmluZWQgJiYgaGFzQ2hhbmdlZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Byb3BlcnR5IFxcJycgKyBhdHRyICsgJ1xcJyBjYW4gb25seSBiZSBzZXQgb25jZS4nKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gc2V0L3Vuc2V0IGF0dHJpYnV0ZXMuXG4gICAgICAgICAgICAvLyBJZiB0aGlzIGlzIG5vdCB0aGUgaW5pdGlhbCBzZXQsIGtlZXAgdHJhY2sgb2YgY2hhbmdlZCBhdHRyaWJ1dGVzXG4gICAgICAgICAgICAvLyBhbmQgcHVzaCB0byBjaGFuZ2VFdmVudHMgYXJyYXkgc28gd2UgY2FuIGZpcmUgZXZlbnRzLlxuICAgICAgICAgICAgaWYgKGhhc0NoYW5nZWQpIHtcblxuICAgICAgICAgICAgICAgIC8vIFRoaXMgZmlyZXMgbm8gbWF0dGVyIHdoYXQsIGV2ZW4gb24gaW5pdGlhbCBzZXQuXG4gICAgICAgICAgICAgICAgb25DaGFuZ2UobmV3VmFsLCBjdXJyZW50VmFsLCBhdHRyKTtcblxuICAgICAgICAgICAgICAgIC8vIElmIHRoaXMgaXMgYSBjaGFuZ2UgKG5vdCBhbiBpbml0aWFsIHNldCksIG1hcmsgdGhlIGNoYW5nZS5cbiAgICAgICAgICAgICAgICAvLyBOb3RlIGl0J3MgaW1wb3NzaWJsZSB0byB1bnNldCBvbiB0aGUgaW5pdGlhbCBzZXQgKGl0IHdpbGwgYWxyZWFkeSBiZSB1bnNldCksXG4gICAgICAgICAgICAgICAgLy8gc28gd2Ugb25seSBpbmNsdWRlIHRoYXQgbG9naWMgaGVyZS5cbiAgICAgICAgICAgICAgICBpZiAoIWluaXRpYWwpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fY2hhbmdlZFthdHRyXSA9IG5ld1ZhbDtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzW2F0dHJdID0gY3VycmVudFZhbDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHVuc2V0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBGSVhNRSBkZWxldGUgaXMgdmVyeSBzbG93LiBDYW4gd2UgZ2V0IGF3YXkgd2l0aCBzZXR0aW5nIHRvIHVuZGVmaW5lZD9cbiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLl92YWx1ZXNbYXR0cl07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFzaWxlbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNoYW5nZUV2ZW50cy5wdXNoKHtwcmV2OiBjdXJyZW50VmFsLCB2YWw6IG5ld1ZhbCwga2V5OiBhdHRyfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCF1bnNldCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl92YWx1ZXNbYXR0cl0gPSBuZXdWYWw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBOb3QgY2hhbmdlZFxuICAgICAgICAgICAgICAgIC8vIEZJWE1FIGRlbGV0ZSBpcyB2ZXJ5IHNsb3cuIENhbiB3ZSBnZXQgYXdheSB3aXRoIHNldHRpbmcgdG8gdW5kZWZpbmVkP1xuICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLl9jaGFuZ2VkW2F0dHJdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gRmlyZSBldmVudHMuIFRoaXMgYXJyYXkgaXMgbm90IHBvcHVsYXRlZCBpZiB3ZSBhcmUgdG9sZCB0byBiZSBzaWxlbnQuXG4gICAgICAgIGlmIChjaGFuZ2VFdmVudHMubGVuZ3RoKSB0aGlzLl9wZW5kaW5nID0gdHJ1ZTtcbiAgICAgICAgY2hhbmdlRXZlbnRzLmZvckVhY2goZnVuY3Rpb24gKGNoYW5nZSkge1xuICAgICAgICAgICAgc2VsZi50cmlnZ2VyKCdjaGFuZ2U6JyArIGNoYW5nZS5rZXksIHNlbGYsIGNoYW5nZS52YWwsIG9wdGlvbnMpO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBZb3UgbWlnaHQgYmUgd29uZGVyaW5nIHdoeSB0aGVyZSdzIGEgYHdoaWxlYCBsb29wIGhlcmUuIENoYW5nZXMgY2FuXG4gICAgICAgIC8vIGJlIHJlY3Vyc2l2ZWx5IG5lc3RlZCB3aXRoaW4gYFwiY2hhbmdlXCJgIGV2ZW50cy5cbiAgICAgICAgaWYgKHdhc0NoYW5naW5nKSByZXR1cm4gdGhpcztcbiAgICAgICAgd2hpbGUgKHRoaXMuX3BlbmRpbmcpIHtcbiAgICAgICAgICAgIHRoaXMuX3BlbmRpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMudHJpZ2dlcignY2hhbmdlJywgdGhpcywgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fcGVuZGluZyA9IGZhbHNlO1xuICAgICAgICB0aGlzLl9jaGFuZ2luZyA9IGZhbHNlO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuXG4gICAgZ2V0OiBmdW5jdGlvbiAoYXR0cikge1xuICAgICAgICByZXR1cm4gdGhpc1thdHRyXTtcbiAgICB9LFxuXG4gICAgLy8gVG9nZ2xlIGJvb2xlYW4gcHJvcGVydGllcyBvciBwcm9wZXJ0aWVzIHRoYXQgaGF2ZSBhIGB2YWx1ZXNgXG4gICAgLy8gYXJyYXkgaW4gaXRzIGRlZmluaXRpb24uXG4gICAgdG9nZ2xlOiBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgdmFyIGRlZiA9IHRoaXMuX2RlZmluaXRpb25bcHJvcGVydHldO1xuICAgICAgICBpZiAoZGVmLnR5cGUgPT09ICdib29sZWFuJykge1xuICAgICAgICAgICAgLy8gaWYgaXQncyBhIGJvb2wsIGp1c3QgZmxpcCBpdFxuICAgICAgICAgICAgdGhpc1twcm9wZXJ0eV0gPSAhdGhpc1twcm9wZXJ0eV07XG4gICAgICAgIH0gZWxzZSBpZiAoZGVmICYmIGRlZi52YWx1ZXMpIHtcbiAgICAgICAgICAgIC8vIElmIGl0J3MgYSBwcm9wZXJ0eSB3aXRoIGFuIGFycmF5IG9mIHZhbHVlc1xuICAgICAgICAgICAgLy8gc2tpcCB0byB0aGUgbmV4dCBvbmUgbG9vcGluZyBiYWNrIGlmIGF0IGVuZC5cbiAgICAgICAgICAgIHRoaXNbcHJvcGVydHldID0gYXJyYXlOZXh0KGRlZi52YWx1ZXMsIHRoaXNbcHJvcGVydHldKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0NhbiBvbmx5IHRvZ2dsZSBwcm9wZXJ0aWVzIHRoYXQgYXJlIHR5cGUgYGJvb2xlYW5gIG9yIGhhdmUgYHZhbHVlc2AgYXJyYXkuJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIC8vIEdldCBhbGwgb2YgdGhlIGF0dHJpYnV0ZXMgb2YgdGhlIG1vZGVsIGF0IHRoZSB0aW1lIG9mIHRoZSBwcmV2aW91c1xuICAgIC8vIGBcImNoYW5nZVwiYCBldmVudC5cbiAgICBwcmV2aW91c0F0dHJpYnV0ZXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGNsb25lT2JqKHRoaXMuX3ByZXZpb3VzQXR0cmlidXRlcyk7XG4gICAgfSxcblxuICAgIC8vIERldGVybWluZSBpZiB0aGUgbW9kZWwgaGFzIGNoYW5nZWQgc2luY2UgdGhlIGxhc3QgYFwiY2hhbmdlXCJgIGV2ZW50LlxuICAgIC8vIElmIHlvdSBzcGVjaWZ5IGFuIGF0dHJpYnV0ZSBuYW1lLCBkZXRlcm1pbmUgaWYgdGhhdCBhdHRyaWJ1dGUgaGFzIGNoYW5nZWQuXG4gICAgaGFzQ2hhbmdlZDogZnVuY3Rpb24gKGF0dHIpIHtcbiAgICAgICAgaWYgKGF0dHIgPT0gbnVsbCkgcmV0dXJuICEhT2JqZWN0LmtleXModGhpcy5fY2hhbmdlZCkubGVuZ3RoO1xuICAgICAgICBpZiAoaGFzKHRoaXMuX2Rlcml2ZWQsIGF0dHIpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fZGVyaXZlZFthdHRyXS5kZXBMaXN0LnNvbWUoZnVuY3Rpb24gKGRlcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmhhc0NoYW5nZWQoZGVwKTtcbiAgICAgICAgICAgIH0sIHRoaXMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBoYXModGhpcy5fY2hhbmdlZCwgYXR0cik7XG4gICAgfSxcblxuICAgIC8vIFJldHVybiBhbiBvYmplY3QgY29udGFpbmluZyBhbGwgdGhlIGF0dHJpYnV0ZXMgdGhhdCBoYXZlIGNoYW5nZWQsIG9yXG4gICAgLy8gZmFsc2UgaWYgdGhlcmUgYXJlIG5vIGNoYW5nZWQgYXR0cmlidXRlcy4gVXNlZnVsIGZvciBkZXRlcm1pbmluZyB3aGF0XG4gICAgLy8gcGFydHMgb2YgYSB2aWV3IG5lZWQgdG8gYmUgdXBkYXRlZCBhbmQvb3Igd2hhdCBhdHRyaWJ1dGVzIG5lZWQgdG8gYmVcbiAgICAvLyBwZXJzaXN0ZWQgdG8gdGhlIHNlcnZlci4gVW5zZXQgYXR0cmlidXRlcyB3aWxsIGJlIHNldCB0byB1bmRlZmluZWQuXG4gICAgLy8gWW91IGNhbiBhbHNvIHBhc3MgYW4gYXR0cmlidXRlcyBvYmplY3QgdG8gZGlmZiBhZ2FpbnN0IHRoZSBtb2RlbCxcbiAgICAvLyBkZXRlcm1pbmluZyBpZiB0aGVyZSAqd291bGQgYmUqIGEgY2hhbmdlLlxuICAgIGNoYW5nZWRBdHRyaWJ1dGVzOiBmdW5jdGlvbiAoZGlmZikge1xuICAgICAgICBpZiAoIWRpZmYpIHJldHVybiB0aGlzLmhhc0NoYW5nZWQoKSA/IGNsb25lT2JqKHRoaXMuX2NoYW5nZWQpIDogZmFsc2U7XG4gICAgICAgIHZhciB2YWwsIGNoYW5nZWQgPSBmYWxzZTtcbiAgICAgICAgdmFyIG9sZCA9IHRoaXMuX2NoYW5naW5nID8gdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzIDogdGhpcy5hdHRyaWJ1dGVzO1xuICAgICAgICB2YXIgZGVmLCBpc0VxdWFsO1xuICAgICAgICBmb3IgKHZhciBhdHRyIGluIGRpZmYpIHtcbiAgICAgICAgICAgIGRlZiA9IHRoaXMuX2RlZmluaXRpb25bYXR0cl07XG4gICAgICAgICAgICBpZiAoIWRlZikgY29udGludWU7XG4gICAgICAgICAgICBpc0VxdWFsID0gdGhpcy5fZ2V0Q29tcGFyZUZvclR5cGUoZGVmLnR5cGUpO1xuICAgICAgICAgICAgaWYgKGlzRXF1YWwob2xkW2F0dHJdLCAodmFsID0gZGlmZlthdHRyXSkpKSBjb250aW51ZTtcbiAgICAgICAgICAgIChjaGFuZ2VkIHx8IChjaGFuZ2VkID0ge30pKVthdHRyXSA9IHZhbDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY2hhbmdlZDtcbiAgICB9LFxuXG4gICAgdG9KU09OOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlcmlhbGl6ZSgpO1xuICAgIH0sXG5cbiAgICB1bnNldDogZnVuY3Rpb24gKGF0dHJzLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgYXR0cnMgPSBBcnJheS5pc0FycmF5KGF0dHJzKSA/IGF0dHJzIDogW2F0dHJzXTtcbiAgICAgICAgYXR0cnMuZm9yRWFjaChmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICB2YXIgZGVmID0gc2VsZi5fZGVmaW5pdGlvbltrZXldO1xuICAgICAgICAgICAgaWYgKCFkZWYpIHJldHVybjtcbiAgICAgICAgICAgIHZhciB2YWw7XG4gICAgICAgICAgICBpZiAoZGVmLnJlcXVpcmVkKSB7XG4gICAgICAgICAgICAgICAgdmFsID0gcmVzdWx0KGRlZiwgJ2RlZmF1bHQnKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gc2VsZi5zZXQoa2V5LCB2YWwsIG9wdGlvbnMpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc2VsZi5zZXQoa2V5LCB2YWwsIGFzc2lnbih7fSwgb3B0aW9ucywge3Vuc2V0OiB0cnVlfSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgY2xlYXI6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgT2JqZWN0LmtleXModGhpcy5hdHRyaWJ1dGVzKS5mb3JFYWNoKGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHNlbGYudW5zZXQoa2V5LCBvcHRpb25zKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICBwcmV2aW91czogZnVuY3Rpb24gKGF0dHIpIHtcbiAgICAgICAgaWYgKGF0dHIgPT0gbnVsbCB8fCAhT2JqZWN0LmtleXModGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzKS5sZW5ndGgpIHJldHVybiBudWxsO1xuICAgICAgICByZXR1cm4gdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzW2F0dHJdO1xuICAgIH0sXG5cbiAgICAvLyBHZXQgZGVmYXVsdCB2YWx1ZXMgZm9yIGEgY2VydGFpbiB0eXBlXG4gICAgX2dldERlZmF1bHRGb3JUeXBlOiBmdW5jdGlvbiAodHlwZSkge1xuICAgICAgICB2YXIgZGF0YVR5cGUgPSB0aGlzLl9kYXRhVHlwZXNbdHlwZV07XG4gICAgICAgIHJldHVybiBkYXRhVHlwZSAmJiBkYXRhVHlwZVsnZGVmYXVsdCddO1xuICAgIH0sXG5cbiAgICAvLyBEZXRlcm1pbmUgd2hpY2ggY29tcGFyaXNvbiBhbGdvcml0aG0gdG8gdXNlIGZvciBjb21wYXJpbmcgYSBwcm9wZXJ0eVxuICAgIF9nZXRDb21wYXJlRm9yVHlwZTogZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgICAgdmFyIGRhdGFUeXBlID0gdGhpcy5fZGF0YVR5cGVzW3R5cGVdO1xuICAgICAgICBpZiAoZGF0YVR5cGUgJiYgZGF0YVR5cGUuY29tcGFyZSkgcmV0dXJuIGRhdGFUeXBlLmNvbXBhcmUuYmluZCh0aGlzKTtcbiAgICAgICAgcmV0dXJuIF9pc0VxdWFsOyAvLyBpZiBubyBjb21wYXJlIGZ1bmN0aW9uIGlzIGRlZmluZWQsIHVzZSBfLmlzRXF1YWxcbiAgICB9LFxuXG4gICAgX2dldE9uQ2hhbmdlRm9yVHlwZSA6IGZ1bmN0aW9uKHR5cGUpe1xuICAgICAgICB2YXIgZGF0YVR5cGUgPSB0aGlzLl9kYXRhVHlwZXNbdHlwZV07XG4gICAgICAgIGlmIChkYXRhVHlwZSAmJiBkYXRhVHlwZS5vbkNoYW5nZSkgcmV0dXJuIGRhdGFUeXBlLm9uQ2hhbmdlLmJpbmQodGhpcyk7XG4gICAgICAgIHJldHVybiBub29wO1xuICAgIH0sXG5cbiAgICAvLyBSdW4gdmFsaWRhdGlvbiBhZ2FpbnN0IHRoZSBuZXh0IGNvbXBsZXRlIHNldCBvZiBtb2RlbCBhdHRyaWJ1dGVzLFxuICAgIC8vIHJldHVybmluZyBgdHJ1ZWAgaWYgYWxsIGlzIHdlbGwuIE90aGVyd2lzZSwgZmlyZSBhbiBgXCJpbnZhbGlkXCJgIGV2ZW50LlxuICAgIF92YWxpZGF0ZTogZnVuY3Rpb24gKGF0dHJzLCBvcHRpb25zKSB7XG4gICAgICAgIGlmICghb3B0aW9ucy52YWxpZGF0ZSB8fCAhdGhpcy52YWxpZGF0ZSkgcmV0dXJuIHRydWU7XG4gICAgICAgIGF0dHJzID0gYXNzaWduKHt9LCB0aGlzLmF0dHJpYnV0ZXMsIGF0dHJzKTtcbiAgICAgICAgdmFyIGVycm9yID0gdGhpcy52YWxpZGF0aW9uRXJyb3IgPSB0aGlzLnZhbGlkYXRlKGF0dHJzLCBvcHRpb25zKSB8fCBudWxsO1xuICAgICAgICBpZiAoIWVycm9yKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgdGhpcy50cmlnZ2VyKCdpbnZhbGlkJywgdGhpcywgZXJyb3IsIGFzc2lnbihvcHRpb25zIHx8IHt9LCB7dmFsaWRhdGlvbkVycm9yOiBlcnJvcn0pKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0sXG5cbiAgICBfY3JlYXRlUHJvcGVydHlEZWZpbml0aW9uOiBmdW5jdGlvbiAobmFtZSwgZGVzYywgaXNTZXNzaW9uKSB7XG4gICAgICAgIHJldHVybiBjcmVhdGVQcm9wZXJ0eURlZmluaXRpb24odGhpcywgbmFtZSwgZGVzYywgaXNTZXNzaW9uKTtcbiAgICB9LFxuXG4gICAgLy8ganVzdCBtYWtlcyBmcmllbmRsaWVyIGVycm9ycyB3aGVuIHRyeWluZyB0byBkZWZpbmUgYSBuZXcgbW9kZWxcbiAgICAvLyBvbmx5IHVzZWQgd2hlbiBzZXR0aW5nIHVwIG9yaWdpbmFsIHByb3BlcnR5IGRlZmluaXRpb25zXG4gICAgX2Vuc3VyZVZhbGlkVHlwZTogZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgICAgcmV0dXJuIGluY2x1ZGVzKFsnc3RyaW5nJywgJ251bWJlcicsICdib29sZWFuJywgJ2FycmF5JywgJ29iamVjdCcsICdkYXRlJywgJ3N0YXRlJywgJ2FueSddXG4gICAgICAgICAgICAuY29uY2F0KE9iamVjdC5rZXlzKHRoaXMuX2RhdGFUeXBlcykpLCB0eXBlKSA/IHR5cGUgOiB1bmRlZmluZWQ7XG4gICAgfSxcblxuICAgIGdldEF0dHJpYnV0ZXM6IGZ1bmN0aW9uIChvcHRpb25zLCByYXcpIHtcbiAgICAgICAgb3B0aW9ucyA9IGFzc2lnbih7XG4gICAgICAgICAgICBzZXNzaW9uOiBmYWxzZSxcbiAgICAgICAgICAgIHByb3BzOiBmYWxzZSxcbiAgICAgICAgICAgIGRlcml2ZWQ6IGZhbHNlXG4gICAgICAgIH0sIG9wdGlvbnMgfHwge30pO1xuICAgICAgICB2YXIgcmVzID0ge307XG4gICAgICAgIHZhciB2YWwsIGRlZjtcbiAgICAgICAgZm9yICh2YXIgaXRlbSBpbiB0aGlzLl9kZWZpbml0aW9uKSB7XG4gICAgICAgICAgICBkZWYgPSB0aGlzLl9kZWZpbml0aW9uW2l0ZW1dO1xuICAgICAgICAgICAgaWYgKChvcHRpb25zLnNlc3Npb24gJiYgZGVmLnNlc3Npb24pIHx8IChvcHRpb25zLnByb3BzICYmICFkZWYuc2Vzc2lvbikpIHtcbiAgICAgICAgICAgICAgICB2YWwgPSByYXcgPyB0aGlzLl92YWx1ZXNbaXRlbV0gOiB0aGlzW2l0ZW1dO1xuICAgICAgICAgICAgICAgIGlmIChyYXcgJiYgdmFsICYmIGlzRnVuY3Rpb24odmFsLnNlcmlhbGl6ZSkpIHZhbCA9IHZhbC5zZXJpYWxpemUoKTtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbCA9PT0gJ3VuZGVmaW5lZCcpIHZhbCA9IHJlc3VsdChkZWYsICdkZWZhdWx0Jyk7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWwgIT09ICd1bmRlZmluZWQnKSByZXNbaXRlbV0gPSB2YWw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZGVyaXZlZCkge1xuICAgICAgICAgICAgZm9yICh2YXIgZGVyaXZlZEl0ZW0gaW4gdGhpcy5fZGVyaXZlZCkgcmVzW2Rlcml2ZWRJdGVtXSA9IHRoaXNbZGVyaXZlZEl0ZW1dO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfSxcblxuICAgIF9pbml0RGVyaXZlZDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgZm9yT3duKHRoaXMuX2Rlcml2ZWQsIGZ1bmN0aW9uICh2YWx1ZSwgbmFtZSkge1xuICAgICAgICAgICAgdmFyIGRlZiA9IHNlbGYuX2Rlcml2ZWRbbmFtZV07XG4gICAgICAgICAgICBkZWYuZGVwcyA9IGRlZi5kZXBMaXN0O1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBuZXdWYWwgPSBkZWYuZm4uY2FsbChzZWxmKTtcblxuICAgICAgICAgICAgICAgIGlmIChzZWxmLl9jYWNoZVtuYW1lXSAhPT0gbmV3VmFsIHx8ICFkZWYuY2FjaGUpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGRlZi5jYWNoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fcHJldmlvdXNBdHRyaWJ1dGVzW25hbWVdID0gc2VsZi5fY2FjaGVbbmFtZV07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgc2VsZi5fY2FjaGVbbmFtZV0gPSBuZXdWYWw7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYudHJpZ2dlcignY2hhbmdlOicgKyBuYW1lLCBzZWxmLCBzZWxmLl9jYWNoZVtuYW1lXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZGVmLmRlcHMuZm9yRWFjaChmdW5jdGlvbiAocHJvcFN0cmluZykge1xuICAgICAgICAgICAgICAgIHNlbGYuX2tleVRyZWUuYWRkKHByb3BTdHJpbmcsIHVwZGF0ZSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5vbignYWxsJywgZnVuY3Rpb24gKGV2ZW50TmFtZSkge1xuICAgICAgICAgICAgaWYgKGNoYW5nZVJFLnRlc3QoZXZlbnROYW1lKSkge1xuICAgICAgICAgICAgICAgIHNlbGYuX2tleVRyZWUuZ2V0KGV2ZW50TmFtZS5zcGxpdCgnOicpWzFdKS5mb3JFYWNoKGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgICAgICAgICBmbigpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LCB0aGlzKTtcbiAgICB9LFxuXG4gICAgX2dldERlcml2ZWRQcm9wZXJ0eTogZnVuY3Rpb24gKG5hbWUsIGZsdXNoQ2FjaGUpIHtcbiAgICAgICAgLy8gaXMgdGhpcyBhIGRlcml2ZWQgcHJvcGVydHkgdGhhdCBpcyBjYWNoZWRcbiAgICAgICAgaWYgKHRoaXMuX2Rlcml2ZWRbbmFtZV0uY2FjaGUpIHtcbiAgICAgICAgICAgIC8vc2V0IGlmIHRoaXMgaXMgdGhlIGZpcnN0IHRpbWUsIG9yIGZsdXNoQ2FjaGUgaXMgc2V0XG4gICAgICAgICAgICBpZiAoZmx1c2hDYWNoZSB8fCAhdGhpcy5fY2FjaGUuaGFzT3duUHJvcGVydHkobmFtZSkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9jYWNoZVtuYW1lXSA9IHRoaXMuX2Rlcml2ZWRbbmFtZV0uZm4uYXBwbHkodGhpcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fY2FjaGVbbmFtZV07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fZGVyaXZlZFtuYW1lXS5mbi5hcHBseSh0aGlzKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfaW5pdENvbGxlY3Rpb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBjb2xsO1xuICAgICAgICBpZiAoIXRoaXMuX2NvbGxlY3Rpb25zKSByZXR1cm47XG4gICAgICAgIGZvciAoY29sbCBpbiB0aGlzLl9jb2xsZWN0aW9ucykge1xuICAgICAgICAgICAgdGhpcy5fc2FmZVNldChjb2xsLCBuZXcgdGhpcy5fY29sbGVjdGlvbnNbY29sbF0obnVsbCwge3BhcmVudDogdGhpc30pKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfaW5pdENoaWxkcmVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBjaGlsZDtcbiAgICAgICAgaWYgKCF0aGlzLl9jaGlsZHJlbikgcmV0dXJuO1xuICAgICAgICBmb3IgKGNoaWxkIGluIHRoaXMuX2NoaWxkcmVuKSB7XG4gICAgICAgICAgICB0aGlzLl9zYWZlU2V0KGNoaWxkLCBuZXcgdGhpcy5fY2hpbGRyZW5bY2hpbGRdKHt9LCB7cGFyZW50OiB0aGlzfSkpO1xuICAgICAgICAgICAgdGhpcy5saXN0ZW5Ubyh0aGlzW2NoaWxkXSwgJ2FsbCcsIHRoaXMuX2dldENhY2hlZEV2ZW50QnViYmxpbmdIYW5kbGVyKGNoaWxkKSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLy8gUmV0dXJucyBhIGJvdW5kIGhhbmRsZXIgZm9yIGRvaW5nIGV2ZW50IGJ1YmJsaW5nIHdoaWxlXG4gICAgLy8gYWRkaW5nIGEgbmFtZSB0byB0aGUgY2hhbmdlIHN0cmluZy5cbiAgICBfZ2V0Q2FjaGVkRXZlbnRCdWJibGluZ0hhbmRsZXI6IGZ1bmN0aW9uIChwcm9wZXJ0eU5hbWUpIHtcbiAgICAgICAgaWYgKCF0aGlzLl9ldmVudEJ1YmJsaW5nSGFuZGxlckNhY2hlW3Byb3BlcnR5TmFtZV0pIHtcbiAgICAgICAgICAgIHRoaXMuX2V2ZW50QnViYmxpbmdIYW5kbGVyQ2FjaGVbcHJvcGVydHlOYW1lXSA9IGZ1bmN0aW9uIChuYW1lLCBtb2RlbCwgbmV3VmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAoY2hhbmdlUkUudGVzdChuYW1lKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnRyaWdnZXIoJ2NoYW5nZTonICsgcHJvcGVydHlOYW1lICsgJy4nICsgbmFtZS5zcGxpdCgnOicpWzFdLCBtb2RlbCwgbmV3VmFsdWUpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobmFtZSA9PT0gJ2NoYW5nZScpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy50cmlnZ2VyKCdjaGFuZ2UnLCB0aGlzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LmJpbmQodGhpcyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuX2V2ZW50QnViYmxpbmdIYW5kbGVyQ2FjaGVbcHJvcGVydHlOYW1lXTtcbiAgICB9LFxuXG4gICAgLy8gQ2hlY2sgdGhhdCBhbGwgcmVxdWlyZWQgYXR0cmlidXRlcyBhcmUgcHJlc2VudFxuICAgIF92ZXJpZnlSZXF1aXJlZDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgYXR0cnMgPSB0aGlzLmF0dHJpYnV0ZXM7IC8vIHNob3VsZCBpbmNsdWRlIHNlc3Npb25cbiAgICAgICAgZm9yICh2YXIgZGVmIGluIHRoaXMuX2RlZmluaXRpb24pIHtcbiAgICAgICAgICAgIGlmICh0aGlzLl9kZWZpbml0aW9uW2RlZl0ucmVxdWlyZWQgJiYgdHlwZW9mIGF0dHJzW2RlZl0gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0sXG5cbiAgICAvLyBleHBvc2Ugc2FmZVNldCBtZXRob2RcbiAgICBfc2FmZVNldDogZnVuY3Rpb24gc2FmZVNldChwcm9wZXJ0eSwgdmFsdWUpIHtcbiAgICAgICAgaWYgKHByb3BlcnR5IGluIHRoaXMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignRW5jb3VudGVyZWQgbmFtZXNwYWNlIGNvbGxpc2lvbiB3aGlsZSBzZXR0aW5nIGluc3RhbmNlIHByb3BlcnR5IGAnICsgcHJvcGVydHkgKyAnYCcpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXNbcHJvcGVydHldID0gdmFsdWU7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbn0pO1xuXG4vLyBnZXR0ZXIgZm9yIGF0dHJpYnV0ZXNcbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEJhc2UucHJvdG90eXBlLCB7XG4gICAgYXR0cmlidXRlczoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldEF0dHJpYnV0ZXMoe3Byb3BzOiB0cnVlLCBzZXNzaW9uOiB0cnVlfSk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGFsbDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAgIHNlc3Npb246IHRydWUsXG4gICAgICAgICAgICAgICAgcHJvcHM6IHRydWUsXG4gICAgICAgICAgICAgICAgZGVyaXZlZDogdHJ1ZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGlzU3RhdGU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7IHJldHVybiB0cnVlOyB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICgpIHsgfVxuICAgIH1cbn0pO1xuXG4vLyBoZWxwZXIgZm9yIGNyZWF0aW5nL3N0b3JpbmcgcHJvcGVydHkgZGVmaW5pdGlvbnMgYW5kIGNyZWF0aW5nXG4vLyBhcHByb3ByaWF0ZSBnZXR0ZXJzL3NldHRlcnNcbmZ1bmN0aW9uIGNyZWF0ZVByb3BlcnR5RGVmaW5pdGlvbihvYmplY3QsIG5hbWUsIGRlc2MsIGlzU2Vzc2lvbikge1xuICAgIHZhciBkZWYgPSBvYmplY3QuX2RlZmluaXRpb25bbmFtZV0gPSB7fTtcbiAgICB2YXIgdHlwZSwgZGVzY0FycmF5O1xuXG4gICAgaWYgKGlzU3RyaW5nKGRlc2MpKSB7XG4gICAgICAgIC8vIGdyYWIgb3VyIHR5cGUgaWYgYWxsIHdlJ3ZlIGdvdCBpcyBhIHN0cmluZ1xuICAgICAgICB0eXBlID0gb2JqZWN0Ll9lbnN1cmVWYWxpZFR5cGUoZGVzYyk7XG4gICAgICAgIGlmICh0eXBlKSBkZWYudHlwZSA9IHR5cGU7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy9UcmFuc2Zvcm0gYXJyYXkgb2YgWyd0eXBlJywgcmVxdWlyZWQsIGRlZmF1bHRdIHRvIG9iamVjdCBmb3JtXG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KGRlc2MpKSB7XG4gICAgICAgICAgICBkZXNjQXJyYXkgPSBkZXNjO1xuICAgICAgICAgICAgZGVzYyA9IHtcbiAgICAgICAgICAgICAgICB0eXBlOiBkZXNjQXJyYXlbMF0sXG4gICAgICAgICAgICAgICAgcmVxdWlyZWQ6IGRlc2NBcnJheVsxXSxcbiAgICAgICAgICAgICAgICAnZGVmYXVsdCc6IGRlc2NBcnJheVsyXVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHR5cGUgPSBvYmplY3QuX2Vuc3VyZVZhbGlkVHlwZShkZXNjLnR5cGUpO1xuICAgICAgICBpZiAodHlwZSkgZGVmLnR5cGUgPSB0eXBlO1xuXG4gICAgICAgIGlmIChkZXNjLnJlcXVpcmVkKSBkZWYucmVxdWlyZWQgPSB0cnVlO1xuXG4gICAgICAgIGlmIChkZXNjWydkZWZhdWx0J10gJiYgdHlwZW9mIGRlc2NbJ2RlZmF1bHQnXSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1RoZSBkZWZhdWx0IHZhbHVlIGZvciAnICsgbmFtZSArICcgY2Fubm90IGJlIGFuIG9iamVjdC9hcnJheSwgbXVzdCBiZSBhIHZhbHVlIG9yIGEgZnVuY3Rpb24gd2hpY2ggcmV0dXJucyBhIHZhbHVlL29iamVjdC9hcnJheScpO1xuICAgICAgICB9XG5cbiAgICAgICAgZGVmWydkZWZhdWx0J10gPSBkZXNjWydkZWZhdWx0J107XG5cbiAgICAgICAgZGVmLmFsbG93TnVsbCA9IGRlc2MuYWxsb3dOdWxsID8gZGVzYy5hbGxvd051bGwgOiBmYWxzZTtcbiAgICAgICAgaWYgKGRlc2Muc2V0T25jZSkgZGVmLnNldE9uY2UgPSB0cnVlO1xuICAgICAgICBpZiAoZGVmLnJlcXVpcmVkICYmIGRlZlsnZGVmYXVsdCddID09PSB1bmRlZmluZWQgJiYgIWRlZi5zZXRPbmNlKSBkZWZbJ2RlZmF1bHQnXSA9IG9iamVjdC5fZ2V0RGVmYXVsdEZvclR5cGUodHlwZSk7XG4gICAgICAgIGRlZi50ZXN0ID0gZGVzYy50ZXN0O1xuICAgICAgICBkZWYudmFsdWVzID0gZGVzYy52YWx1ZXM7XG4gICAgfVxuICAgIGlmIChpc1Nlc3Npb24pIGRlZi5zZXNzaW9uID0gdHJ1ZTtcblxuICAgIGlmICghdHlwZSkge1xuICAgICAgICB0eXBlID0gaXNTdHJpbmcoZGVzYykgPyBkZXNjIDogZGVzYy50eXBlO1xuICAgICAgICAvLyBUT0RPOiBzdGFydCB0aHJvd2luZyBhIFR5cGVFcnJvciBpbiBmdXR1cmUgbWFqb3IgdmVyc2lvbnMgaW5zdGVhZCBvZiB3YXJuaW5nXG4gICAgICAgIGNvbnNvbGUud2FybignSW52YWxpZCBkYXRhIHR5cGUgb2YgYCcgKyB0eXBlICsgJ2AgZm9yIGAnICsgbmFtZSArICdgIHByb3BlcnR5LiBVc2Ugb25lIG9mIHRoZSBkZWZhdWx0IHR5cGVzIG9yIGRlZmluZSB5b3VyIG93bicpO1xuICAgIH1cblxuICAgIC8vIGRlZmluZSBhIGdldHRlci9zZXR0ZXIgb24gdGhlIHByb3RvdHlwZVxuICAgIC8vIGJ1dCB0aGV5IGdldC9zZXQgb24gdGhlIGluc3RhbmNlXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iamVjdCwgbmFtZSwge1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWwpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0KG5hbWUsIHZhbCk7XG4gICAgICAgIH0sXG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKCF0aGlzLl92YWx1ZXMpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcignWW91IG1heSBiZSB0cnlpbmcgdG8gYGV4dGVuZGAgYSBzdGF0ZSBvYmplY3Qgd2l0aCBcIicgKyBuYW1lICsgJ1wiIHdoaWNoIGhhcyBiZWVuIGRlZmluZWQgaW4gYHByb3BzYCBvbiB0aGUgb2JqZWN0IGJlaW5nIGV4dGVuZGVkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgdmFsdWUgPSB0aGlzLl92YWx1ZXNbbmFtZV07XG4gICAgICAgICAgICB2YXIgdHlwZURlZiA9IHRoaXMuX2RhdGFUeXBlc1tkZWYudHlwZV07XG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlRGVmICYmIHR5cGVEZWYuZ2V0KSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdHlwZURlZi5nZXQodmFsdWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgZGVmYXVsdFZhbHVlID0gcmVzdWx0KGRlZiwgJ2RlZmF1bHQnKTtcbiAgICAgICAgICAgIHRoaXMuX3ZhbHVlc1tuYW1lXSA9IGRlZmF1bHRWYWx1ZTtcbiAgICAgICAgICAgIC8vIElmIHdlJ3ZlIHNldCBhIGRlZmF1bHRWYWx1ZSwgZmlyZSBhIGNoYW5nZSBoYW5kbGVyIGVmZmVjdGl2ZWx5IG1hcmtpbmdcbiAgICAgICAgICAgIC8vIGl0cyBjaGFuZ2UgZnJvbSB1bmRlZmluZWQgdG8gdGhlIGRlZmF1bHQgdmFsdWUuXG4gICAgICAgICAgICBpZiAodHlwZW9mIGRlZmF1bHRWYWx1ZSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICB2YXIgb25DaGFuZ2UgPSB0aGlzLl9nZXRPbkNoYW5nZUZvclR5cGUoZGVmLnR5cGUpO1xuICAgICAgICAgICAgICAgIG9uQ2hhbmdlKGRlZmF1bHRWYWx1ZSwgdmFsdWUsIG5hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGRlZmF1bHRWYWx1ZTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGRlZjtcbn1cblxuLy8gaGVscGVyIGZvciBjcmVhdGluZyBkZXJpdmVkIHByb3BlcnR5IGRlZmluaXRpb25zXG5mdW5jdGlvbiBjcmVhdGVEZXJpdmVkUHJvcGVydHkobW9kZWxQcm90bywgbmFtZSwgZGVmaW5pdGlvbikge1xuICAgIHZhciBkZWYgPSBtb2RlbFByb3RvLl9kZXJpdmVkW25hbWVdID0ge1xuICAgICAgICBmbjogaXNGdW5jdGlvbihkZWZpbml0aW9uKSA/IGRlZmluaXRpb24gOiBkZWZpbml0aW9uLmZuLFxuICAgICAgICBjYWNoZTogKGRlZmluaXRpb24uY2FjaGUgIT09IGZhbHNlKSxcbiAgICAgICAgZGVwTGlzdDogZGVmaW5pdGlvbi5kZXBzIHx8IFtdXG4gICAgfTtcblxuICAgIC8vIGFkZCB0byBvdXIgc2hhcmVkIGRlcGVuZGVuY3kgbGlzdFxuICAgIGRlZi5kZXBMaXN0LmZvckVhY2goZnVuY3Rpb24gKGRlcCkge1xuICAgICAgICBtb2RlbFByb3RvLl9kZXBzW2RlcF0gPSB1bmlvbihtb2RlbFByb3RvLl9kZXBzW2RlcF0gfHwgW10sIFtuYW1lXSk7XG4gICAgfSk7XG5cbiAgICAvLyBkZWZpbmVkIGEgdG9wLWxldmVsIGdldHRlciBmb3IgZGVyaXZlZCBuYW1lc1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShtb2RlbFByb3RvLCBuYW1lLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2dldERlcml2ZWRQcm9wZXJ0eShuYW1lKTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYFwiICsgbmFtZSArIFwiYCBpcyBhIGRlcml2ZWQgcHJvcGVydHksIGl0IGNhbid0IGJlIHNldCBkaXJlY3RseS5cIik7XG4gICAgICAgIH1cbiAgICB9KTtcbn1cblxudmFyIGRhdGFUeXBlcyA9IHtcbiAgICBzdHJpbmc6IHtcbiAgICAgICAgJ2RlZmF1bHQnOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGRhdGU6IHtcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAobmV3VmFsKSB7XG4gICAgICAgICAgICB2YXIgbmV3VHlwZTtcbiAgICAgICAgICAgIGlmIChuZXdWYWwgPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIG5ld1R5cGUgPSB0eXBlb2YgbnVsbDtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIWlzRGF0ZShuZXdWYWwpKSB7XG4gICAgICAgICAgICAgICAgdmFyIGVyciA9IG51bGw7XG4gICAgICAgICAgICAgICAgdmFyIGRhdGVWYWwgPSBuZXcgRGF0ZShuZXdWYWwpLnZhbHVlT2YoKTtcbiAgICAgICAgICAgICAgICBpZiAoaXNOYU4oZGF0ZVZhbCkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhlIG5ld1ZhbCBjYW50IGJlIHBhcnNlZCwgdGhlbiB0cnkgcGFyc2VJbnQgZmlyc3RcbiAgICAgICAgICAgICAgICAgICAgZGF0ZVZhbCA9IG5ldyBEYXRlKHBhcnNlSW50KG5ld1ZhbCwgMTApKS52YWx1ZU9mKCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpc05hTihkYXRlVmFsKSkgZXJyID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbmV3VmFsID0gZGF0ZVZhbDtcbiAgICAgICAgICAgICAgICBuZXdUeXBlID0gJ2RhdGUnO1xuICAgICAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgbmV3VHlwZSA9IHR5cGVvZiBuZXdWYWw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBuZXdUeXBlID0gJ2RhdGUnO1xuICAgICAgICAgICAgICAgIG5ld1ZhbCA9IG5ld1ZhbC52YWx1ZU9mKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgdmFsOiBuZXdWYWwsXG4gICAgICAgICAgICAgICAgdHlwZTogbmV3VHlwZVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAodmFsKSB7XG4gICAgICAgICAgICBpZiAodmFsID09IG51bGwpIHsgcmV0dXJuIHZhbDsgfVxuICAgICAgICAgICAgcmV0dXJuIG5ldyBEYXRlKHZhbCk7XG4gICAgICAgIH0sXG4gICAgICAgICdkZWZhdWx0JzogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBEYXRlKCk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGFycmF5OiB7XG4gICAgICAgIHNldDogZnVuY3Rpb24gKG5ld1ZhbCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB2YWw6IG5ld1ZhbCxcbiAgICAgICAgICAgICAgICB0eXBlOiBBcnJheS5pc0FycmF5KG5ld1ZhbCkgPyAnYXJyYXknIDogdHlwZW9mIG5ld1ZhbFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgJ2RlZmF1bHQnOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgIH1cbiAgICB9LFxuICAgIG9iamVjdDoge1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChuZXdWYWwpIHtcbiAgICAgICAgICAgIHZhciBuZXdUeXBlID0gdHlwZW9mIG5ld1ZhbDtcbiAgICAgICAgICAgIC8vIHdlIGhhdmUgdG8gaGF2ZSBhIHdheSBvZiBzdXBwb3J0aW5nIFwibWlzc2luZ1wiIG9iamVjdHMuXG4gICAgICAgICAgICAvLyBOdWxsIGlzIGFuIG9iamVjdCwgYnV0IHNldHRpbmcgYSB2YWx1ZSB0byB1bmRlZmluZWRcbiAgICAgICAgICAgIC8vIHNob3VsZCB3b3JrIHRvbywgSU1PLiBXZSBqdXN0IG92ZXJyaWRlIGl0LCBpbiB0aGF0IGNhc2UuXG4gICAgICAgICAgICBpZiAobmV3VHlwZSAhPT0gJ29iamVjdCcgJiYgbmV3VmFsID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBuZXdWYWwgPSBudWxsO1xuICAgICAgICAgICAgICAgIG5ld1R5cGUgPSAnb2JqZWN0JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgdmFsOiBuZXdWYWwsXG4gICAgICAgICAgICAgICAgdHlwZTogbmV3VHlwZVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgJ2RlZmF1bHQnOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4ge307XG4gICAgICAgIH1cbiAgICB9LFxuICAgIC8vIHRoZSBgc3RhdGVgIGRhdGEgdHlwZSBpcyBhIGJpdCBzcGVjaWFsIGluIHRoYXQgc2V0dGluZyBpdCBzaG91bGRcbiAgICAvLyBhbHNvIGJ1YmJsZSBldmVudHNcbiAgICBzdGF0ZToge1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChuZXdWYWwpIHtcbiAgICAgICAgICAgIHZhciBpc0luc3RhbmNlID0gbmV3VmFsIGluc3RhbmNlb2YgQmFzZSB8fCAobmV3VmFsICYmIG5ld1ZhbC5pc1N0YXRlKTtcbiAgICAgICAgICAgIGlmIChpc0luc3RhbmNlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsOiBuZXdWYWwsXG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdzdGF0ZSdcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICB2YWw6IG5ld1ZhbCxcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogdHlwZW9mIG5ld1ZhbFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGNvbXBhcmU6IGZ1bmN0aW9uIChjdXJyZW50VmFsLCBuZXdWYWwpIHtcbiAgICAgICAgICAgIHJldHVybiBjdXJyZW50VmFsID09PSBuZXdWYWw7XG4gICAgICAgIH0sXG5cbiAgICAgICAgb25DaGFuZ2UgOiBmdW5jdGlvbihuZXdWYWwsIHByZXZpb3VzVmFsLCBhdHRyaWJ1dGVOYW1lKXtcbiAgICAgICAgICAgIC8vIGlmIHRoaXMgaGFzIGNoYW5nZWQgd2Ugd2FudCB0byBhbHNvIGhhbmRsZVxuICAgICAgICAgICAgLy8gZXZlbnQgcHJvcGFnYXRpb25cbiAgICAgICAgICAgIGlmIChwcmV2aW91c1ZhbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuc3RvcExpc3RlbmluZyhwcmV2aW91c1ZhbCwgJ2FsbCcsIHRoaXMuX2dldENhY2hlZEV2ZW50QnViYmxpbmdIYW5kbGVyKGF0dHJpYnV0ZU5hbWUpKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKG5ld1ZhbCAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5saXN0ZW5UbyhuZXdWYWwsICdhbGwnLCB0aGlzLl9nZXRDYWNoZWRFdmVudEJ1YmJsaW5nSGFuZGxlcihhdHRyaWJ1dGVOYW1lKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vLyB0aGUgZXh0ZW5kIG1ldGhvZCB1c2VkIHRvIGV4dGVuZCBwcm90b3R5cGVzLCBtYWludGFpbiBpbmhlcml0YW5jZSBjaGFpbnMgZm9yIGluc3RhbmNlb2Zcbi8vIGFuZCBhbGxvdyBmb3IgYWRkaXRpb25zIHRvIHRoZSBtb2RlbCBkZWZpbml0aW9ucy5cbmZ1bmN0aW9uIGV4dGVuZChwcm90b1Byb3BzKSB7XG4gICAgLypqc2hpbnQgdmFsaWR0aGlzOnRydWUqL1xuICAgIHZhciBwYXJlbnQgPSB0aGlzO1xuICAgIHZhciBjaGlsZDtcblxuICAgIC8vIFRoZSBjb25zdHJ1Y3RvciBmdW5jdGlvbiBmb3IgdGhlIG5ldyBzdWJjbGFzcyBpcyBlaXRoZXIgZGVmaW5lZCBieSB5b3VcbiAgICAvLyAodGhlIFwiY29uc3RydWN0b3JcIiBwcm9wZXJ0eSBpbiB5b3VyIGBleHRlbmRgIGRlZmluaXRpb24pLCBvciBkZWZhdWx0ZWRcbiAgICAvLyBieSB1cyB0byBzaW1wbHkgY2FsbCB0aGUgcGFyZW50J3MgY29uc3RydWN0b3IuXG4gICAgaWYgKHByb3RvUHJvcHMgJiYgcHJvdG9Qcm9wcy5oYXNPd25Qcm9wZXJ0eSgnY29uc3RydWN0b3InKSkge1xuICAgICAgICBjaGlsZCA9IHByb3RvUHJvcHMuY29uc3RydWN0b3I7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgY2hpbGQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gcGFyZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gQWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjb25zdHJ1Y3RvciBmdW5jdGlvbiBmcm9tIHBhcmVudFxuICAgIGFzc2lnbihjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIFNldCB0aGUgcHJvdG90eXBlIGNoYWluIHRvIGluaGVyaXQgZnJvbSBgcGFyZW50YCwgd2l0aG91dCBjYWxsaW5nXG4gICAgLy8gYHBhcmVudGAncyBjb25zdHJ1Y3RvciBmdW5jdGlvbi5cbiAgICB2YXIgU3Vycm9nYXRlID0gZnVuY3Rpb24gKCkgeyB0aGlzLmNvbnN0cnVjdG9yID0gY2hpbGQ7IH07XG4gICAgU3Vycm9nYXRlLnByb3RvdHlwZSA9IHBhcmVudC5wcm90b3R5cGU7XG4gICAgY2hpbGQucHJvdG90eXBlID0gbmV3IFN1cnJvZ2F0ZSgpO1xuXG4gICAgLy8gc2V0IHByb3RvdHlwZSBsZXZlbCBvYmplY3RzXG4gICAgY2hpbGQucHJvdG90eXBlLl9kZXJpdmVkID0gIGFzc2lnbih7fSwgcGFyZW50LnByb3RvdHlwZS5fZGVyaXZlZCk7XG4gICAgY2hpbGQucHJvdG90eXBlLl9kZXBzID0gYXNzaWduKHt9LCBwYXJlbnQucHJvdG90eXBlLl9kZXBzKTtcbiAgICBjaGlsZC5wcm90b3R5cGUuX2RlZmluaXRpb24gPSBhc3NpZ24oe30sIHBhcmVudC5wcm90b3R5cGUuX2RlZmluaXRpb24pO1xuICAgIGNoaWxkLnByb3RvdHlwZS5fY29sbGVjdGlvbnMgPSBhc3NpZ24oe30sIHBhcmVudC5wcm90b3R5cGUuX2NvbGxlY3Rpb25zKTtcbiAgICBjaGlsZC5wcm90b3R5cGUuX2NoaWxkcmVuID0gYXNzaWduKHt9LCBwYXJlbnQucHJvdG90eXBlLl9jaGlsZHJlbik7XG4gICAgY2hpbGQucHJvdG90eXBlLl9kYXRhVHlwZXMgPSBhc3NpZ24oe30sIHBhcmVudC5wcm90b3R5cGUuX2RhdGFUeXBlcyB8fCBkYXRhVHlwZXMpO1xuXG4gICAgLy8gTWl4IGluIGFsbCBwcm90b3R5cGUgcHJvcGVydGllcyB0byB0aGUgc3ViY2xhc3MgaWYgc3VwcGxpZWQuXG4gICAgaWYgKHByb3RvUHJvcHMpIHtcbiAgICAgICAgdmFyIG9taXRGcm9tRXh0ZW5kID0gW1xuICAgICAgICAgICAgJ2RhdGFUeXBlcycsICdwcm9wcycsICdzZXNzaW9uJywgJ2Rlcml2ZWQnLCAnY29sbGVjdGlvbnMnLCAnY2hpbGRyZW4nXG4gICAgICAgIF07XG4gICAgICAgIGZvcih2YXIgaSA9IDA7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHZhciBkZWYgPSBhcmd1bWVudHNbaV07XG4gICAgICAgICAgICBpZiAoZGVmLmRhdGFUeXBlcykge1xuICAgICAgICAgICAgICAgIGZvck93bihkZWYuZGF0YVR5cGVzLCBmdW5jdGlvbiAoZGVmLCBuYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIGNoaWxkLnByb3RvdHlwZS5fZGF0YVR5cGVzW25hbWVdID0gZGVmO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRlZi5wcm9wcykge1xuICAgICAgICAgICAgICAgIGZvck93bihkZWYucHJvcHMsIGZ1bmN0aW9uIChkZWYsIG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgY3JlYXRlUHJvcGVydHlEZWZpbml0aW9uKGNoaWxkLnByb3RvdHlwZSwgbmFtZSwgZGVmKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChkZWYuc2Vzc2lvbikge1xuICAgICAgICAgICAgICAgIGZvck93bihkZWYuc2Vzc2lvbiwgZnVuY3Rpb24gKGRlZiwgbmFtZSkge1xuICAgICAgICAgICAgICAgICAgICBjcmVhdGVQcm9wZXJ0eURlZmluaXRpb24oY2hpbGQucHJvdG90eXBlLCBuYW1lLCBkZWYsIHRydWUpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRlZi5kZXJpdmVkKSB7XG4gICAgICAgICAgICAgICAgZm9yT3duKGRlZi5kZXJpdmVkLCBmdW5jdGlvbiAoZGVmLCBuYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZURlcml2ZWRQcm9wZXJ0eShjaGlsZC5wcm90b3R5cGUsIG5hbWUsIGRlZik7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZGVmLmNvbGxlY3Rpb25zKSB7XG4gICAgICAgICAgICAgICAgZm9yT3duKGRlZi5jb2xsZWN0aW9ucywgZnVuY3Rpb24gKGNvbnN0cnVjdG9yLCBuYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIGNoaWxkLnByb3RvdHlwZS5fY29sbGVjdGlvbnNbbmFtZV0gPSBjb25zdHJ1Y3RvcjtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChkZWYuY2hpbGRyZW4pIHtcbiAgICAgICAgICAgICAgICBmb3JPd24oZGVmLmNoaWxkcmVuLCBmdW5jdGlvbiAoY29uc3RydWN0b3IsIG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgY2hpbGQucHJvdG90eXBlLl9jaGlsZHJlbltuYW1lXSA9IGNvbnN0cnVjdG9yO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXNzaWduKGNoaWxkLnByb3RvdHlwZSwgb21pdChkZWYsIG9taXRGcm9tRXh0ZW5kKSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBTZXQgYSBjb252ZW5pZW5jZSBwcm9wZXJ0eSBpbiBjYXNlIHRoZSBwYXJlbnQncyBwcm90b3R5cGUgaXMgbmVlZGVkXG4gICAgLy8gbGF0ZXIuXG4gICAgY2hpbGQuX19zdXBlcl9fID0gcGFyZW50LnByb3RvdHlwZTtcblxuICAgIHJldHVybiBjaGlsZDtcbn1cblxuQmFzZS5leHRlbmQgPSBleHRlbmQ7XG5cbi8vIE91ciBtYWluIGV4cG9ydHNcbm1vZHVsZS5leHBvcnRzID0gQmFzZTtcbiJdLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTsiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///ef45\n")}}]);

TODO found
Open

(window.webpackJsonp=window.webpackJsonp||[]).push([["npm.ampersand-state"],{ef45:function(module,exports,__webpack_require__){"use strict";eval("\n/*$AMPERSAND_VERSION*/\nvar uniqueId = __webpack_require__(/*! lodash/uniqueId */ \"6d0d\");\nvar assign = __webpack_require__(/*! lodash/assign */ \"5ad5\");\nvar cloneObj = function(obj) { return assign({}, obj); };\nvar omit = __webpack_require__(/*! lodash/omit */ \"4633\");\nvar escape = __webpack_require__(/*! lodash/escape */ \"740c\");\nvar forOwn = __webpack_require__(/*! lodash/forOwn */ \"436f\");\nvar includes = __webpack_require__(/*! lodash/includes */ \"e2c7\");\nvar isString = __webpack_require__(/*! lodash/isString */ \"5fa3\");\nvar isObject = __webpack_require__(/*! lodash/isObject */ \"d3a8\");\nvar isDate = __webpack_require__(/*! lodash/isDate */ \"7f93\");\nvar isFunction = __webpack_require__(/*! lodash/isFunction */ \"f3b0\");\nvar _isEqual = __webpack_require__(/*! lodash/isEqual */ \"f8a3\"); // to avoid shadowing\nvar has = __webpack_require__(/*! lodash/has */ \"b055\");\nvar result = __webpack_require__(/*! lodash/result */ \"80c9\");\nvar union = __webpack_require__(/*! lodash/union */ \"c80f\");\nvar Events = __webpack_require__(/*! ampersand-events */ \"13c2\");\nvar KeyTree = __webpack_require__(/*! key-tree-store */ \"8849\");\nvar arrayNext = __webpack_require__(/*! array-next */ \"d1bb\");\nvar changeRE = /^change:/;\nvar noop = function () {};\n\nfunction Base(attrs, options) {\n    options || (options = {});\n    this.cid || (this.cid = uniqueId('state'));\n    this._events = {};\n    this._values = {};\n    this._eventBubblingHandlerCache = {};\n    this._definition = Object.create(this._definition);\n    if (options.parse) attrs = this.parse(attrs, options);\n    this.parent = options.parent;\n    this.collection = options.collection;\n    this._keyTree = new KeyTree();\n    this._initCollections();\n    this._initChildren();\n    this._cache = {};\n    this._previousAttributes = {};\n    if (attrs) this.set(attrs, assign({silent: true, initial: true}, options));\n    this._changed = {};\n    if (this._derived) this._initDerived();\n    if (options.init !== false) this.initialize.apply(this, arguments);\n}\n\nassign(Base.prototype, Events, {\n    // can be allow, ignore, reject\n    extraProperties: 'ignore',\n\n    idAttribute: 'id',\n\n    namespaceAttribute: 'namespace',\n\n    typeAttribute: 'modelType',\n\n    // Stubbed out to be overwritten\n    initialize: function () {\n        return this;\n    },\n\n    // Get ID of model per configuration.\n    // Should *always* be how ID is determined by other code.\n    getId: function () {\n        return this[this.idAttribute];\n    },\n\n    // Get namespace of model per configuration.\n    // Should *always* be how namespace is determined by other code.\n    getNamespace: function () {\n        return this[this.namespaceAttribute];\n    },\n\n    // Get type of model per configuration.\n    // Should *always* be how type is determined by other code.\n    getType: function () {\n        return this[this.typeAttribute];\n    },\n\n    // A model is new if it has never been saved to the server, and lacks an id.\n    isNew: function () {\n        return this.getId() == null;\n    },\n\n    // get HTML-escaped value of attribute\n    escape: function (attr) {\n        return escape(this.get(attr));\n    },\n\n    // Check if the model is currently in a valid state.\n    isValid: function (options) {\n        return this._validate({}, assign(options || {}, { validate: true }));\n    },\n\n    // Parse can be used remap/restructure/rename incoming properties\n    // before they are applied to attributes.\n    parse: function (resp, options) {\n        //jshint unused:false\n        return resp;\n    },\n\n    // Serialize is the inverse of `parse` it lets you massage data\n    // on the way out. Before, sending to server, for example.\n    serialize: function (options) {\n        var attrOpts = assign({props: true}, options);\n        var res = this.getAttributes(attrOpts, true);\n        \n        var setFromSerializedValue = function (value, key) {\n\t        res[key] = this[key].serialize();\n        }.bind(this);\n        \n        forOwn(this._children, setFromSerializedValue);\n        forOwn(this._collections, setFromSerializedValue);\n        return res;\n    },\n\n    // Main set method used by generated setters/getters and can\n    // be used directly if you need to pass options or set multiple\n    // properties at once.\n    set: function (key, value, options) {\n        var self = this;\n        var extraProperties = this.extraProperties;\n        var wasChanging, changeEvents, newType, newVal, def, cast, err, attr,\n            attrs, dataType, silent, unset, currentVal, initial, hasChanged, isEqual, onChange;\n\n        // Handle both `\"key\", value` and `{key: value}` -style arguments.\n        if (isObject(key) || key === null) {\n            attrs = key;\n            options = value;\n        } else {\n            attrs = {};\n            attrs[key] = value;\n        }\n\n        options = options || {};\n\n        if (!this._validate(attrs, options)) return false;\n\n        // Extract attributes and options.\n        unset = options.unset;\n        silent = options.silent;\n        initial = options.initial;\n\n        // Initialize change tracking.\n        wasChanging = this._changing;\n        this._changing = true;\n        changeEvents = [];\n\n        // if not already changing, store previous\n        if (initial) {\n            this._previousAttributes = {};\n        } else if (!wasChanging) {\n            this._previousAttributes = this.attributes;\n            this._changed = {};\n        }\n\n        // For each `set` attribute...\n        for (var i = 0, keys = Object.keys(attrs), len = keys.length; i < len; i++) {\n            attr = keys[i];\n            newVal = attrs[attr];\n            newType = typeof newVal;\n            currentVal = this._values[attr];\n            def = this._definition[attr];\n\n            if (!def) {\n                // if this is a child model or collection\n                if (this._children[attr] || this._collections[attr]) {\n                    if (!isObject(newVal)) {\n                        newVal = {};\n                    }\n\n                    this[attr].set(newVal, options);\n                    continue;\n                } else if (extraProperties === 'ignore') {\n                    continue;\n                } else if (extraProperties === 'reject') {\n                    throw new TypeError('No \"' + attr + '\" property defined on ' + (this.type || 'this') + ' model and extraProperties not set to \"ignore\" or \"allow\"');\n                } else if (extraProperties === 'allow') {\n                    def = this._createPropertyDefinition(attr, 'any');\n                } else if (extraProperties) {\n                    throw new TypeError('Invalid value for extraProperties: \"' + extraProperties + '\"');\n                }\n            }\n\n            isEqual = this._getCompareForType(def.type);\n            onChange = this._getOnChangeForType(def.type);\n            dataType = this._dataTypes[def.type];\n\n            // check type if we have one\n            if (dataType && dataType.set) {\n                cast = dataType.set(newVal);\n                newVal = cast.val;\n                newType = cast.type;\n            }\n\n            // If we've defined a test, run it\n            if (def.test) {\n                err = def.test.call(this, newVal, newType);\n                if (err) {\n                    throw new TypeError('Property \\'' + attr + '\\' failed validation with error: ' + err);\n                }\n            }\n\n            // If we are required but undefined, throw error.\n            // If we are null and are not allowing null, throw error\n            // If we have a defined type and the new type doesn't match, and we are not null, throw error.\n            // If we require specific value and new one is not one of them, throw error (unless it has default value or we're unsetting it with undefined).\n\n            if (newVal === undefined && def.required) {\n                throw new TypeError('Required property \\'' + attr + '\\' must be of type ' + def.type + '. Tried to set ' + newVal);\n            }\n            if (newVal === null && def.required && !def.allowNull) {\n                throw new TypeError('Property \\'' + attr + '\\' must be of type ' + def.type + ' (cannot be null). Tried to set ' + newVal);\n            }\n            if ((def.type && def.type !== 'any' && def.type !== newType) && newVal !== null && newVal !== undefined) {\n                throw new TypeError('Property \\'' + attr + '\\' must be of type ' + def.type + '. Tried to set ' + newVal);\n            }\n            if (def.values && !includes(def.values, newVal)) {\n                var defaultValue = result(def, 'default');\n                if (unset && defaultValue !== undefined) {\n                    newVal = defaultValue;\n                } else if (!unset || (unset && newVal !== undefined)) {\n                    throw new TypeError('Property \\'' + attr + '\\' must be one of values: ' + def.values.join(', ') + '. Tried to set ' + newVal);\n                }\n            }\n\n            // We know this has 'changed' if it's the initial set, so skip a potentially expensive isEqual check.\n            hasChanged = initial || !isEqual(currentVal, newVal, attr);\n\n            // enforce `setOnce` for properties if set\n            if (def.setOnce && currentVal !== undefined && hasChanged) {\n                throw new TypeError('Property \\'' + attr + '\\' can only be set once.');\n            }\n\n            // set/unset attributes.\n            // If this is not the initial set, keep track of changed attributes\n            // and push to changeEvents array so we can fire events.\n            if (hasChanged) {\n\n                // This fires no matter what, even on initial set.\n                onChange(newVal, currentVal, attr);\n\n                // If this is a change (not an initial set), mark the change.\n                // Note it's impossible to unset on the initial set (it will already be unset),\n                // so we only include that logic here.\n                if (!initial) {\n                    this._changed[attr] = newVal;\n                    this._previousAttributes[attr] = currentVal;\n                    if (unset) {\n                        // FIXME delete is very slow. Can we get away with setting to undefined?\n                        delete this._values[attr];\n                    }\n                    if (!silent) {\n                        changeEvents.push({prev: currentVal, val: newVal, key: attr});\n                    }\n                }\n                if (!unset) {\n                    this._values[attr] = newVal;\n                }\n            } else {\n                // Not changed\n                // FIXME delete is very slow. Can we get away with setting to undefined?\n                delete this._changed[attr];\n            }\n        }\n\n        // Fire events. This array is not populated if we are told to be silent.\n        if (changeEvents.length) this._pending = true;\n        changeEvents.forEach(function (change) {\n            self.trigger('change:' + change.key, self, change.val, options);\n        });\n\n        // You might be wondering why there's a `while` loop here. Changes can\n        // be recursively nested within `\"change\"` events.\n        if (wasChanging) return this;\n        while (this._pending) {\n            this._pending = false;\n            this.trigger('change', this, options);\n        }\n        this._pending = false;\n        this._changing = false;\n        return this;\n    },\n\n    get: function (attr) {\n        return this[attr];\n    },\n\n    // Toggle boolean properties or properties that have a `values`\n    // array in its definition.\n    toggle: function (property) {\n        var def = this._definition[property];\n        if (def.type === 'boolean') {\n            // if it's a bool, just flip it\n            this[property] = !this[property];\n        } else if (def && def.values) {\n            // If it's a property with an array of values\n            // skip to the next one looping back if at end.\n            this[property] = arrayNext(def.values, this[property]);\n        } else {\n            throw new TypeError('Can only toggle properties that are type `boolean` or have `values` array.');\n        }\n        return this;\n    },\n\n    // Get all of the attributes of the model at the time of the previous\n    // `\"change\"` event.\n    previousAttributes: function () {\n        return cloneObj(this._previousAttributes);\n    },\n\n    // Determine if the model has changed since the last `\"change\"` event.\n    // If you specify an attribute name, determine if that attribute has changed.\n    hasChanged: function (attr) {\n        if (attr == null) return !!Object.keys(this._changed).length;\n        if (has(this._derived, attr)) {\n            return this._derived[attr].depList.some(function (dep) {\n                return this.hasChanged(dep);\n            }, this);\n        }\n        return has(this._changed, attr);\n    },\n\n    // Return an object containing all the attributes that have changed, or\n    // false if there are no changed attributes. Useful for determining what\n    // parts of a view need to be updated and/or what attributes need to be\n    // persisted to the server. Unset attributes will be set to undefined.\n    // You can also pass an attributes object to diff against the model,\n    // determining if there *would be* a change.\n    changedAttributes: function (diff) {\n        if (!diff) return this.hasChanged() ? cloneObj(this._changed) : false;\n        var val, changed = false;\n        var old = this._changing ? this._previousAttributes : this.attributes;\n        var def, isEqual;\n        for (var attr in diff) {\n            def = this._definition[attr];\n            if (!def) continue;\n            isEqual = this._getCompareForType(def.type);\n            if (isEqual(old[attr], (val = diff[attr]))) continue;\n            (changed || (changed = {}))[attr] = val;\n        }\n        return changed;\n    },\n\n    toJSON: function () {\n        return this.serialize();\n    },\n\n    unset: function (attrs, options) {\n        var self = this;\n        attrs = Array.isArray(attrs) ? attrs : [attrs];\n        attrs.forEach(function (key) {\n            var def = self._definition[key];\n            if (!def) return;\n            var val;\n            if (def.required) {\n                val = result(def, 'default');\n                return self.set(key, val, options);\n            } else {\n                return self.set(key, val, assign({}, options, {unset: true}));\n            }\n        });\n    },\n\n    clear: function (options) {\n        var self = this;\n        Object.keys(this.attributes).forEach(function (key) {\n            self.unset(key, options);\n        });\n        return this;\n    },\n\n    previous: function (attr) {\n        if (attr == null || !Object.keys(this._previousAttributes).length) return null;\n        return this._previousAttributes[attr];\n    },\n\n    // Get default values for a certain type\n    _getDefaultForType: function (type) {\n        var dataType = this._dataTypes[type];\n        return dataType && dataType['default'];\n    },\n\n    // Determine which comparison algorithm to use for comparing a property\n    _getCompareForType: function (type) {\n        var dataType = this._dataTypes[type];\n        if (dataType && dataType.compare) return dataType.compare.bind(this);\n        return _isEqual; // if no compare function is defined, use _.isEqual\n    },\n\n    _getOnChangeForType : function(type){\n        var dataType = this._dataTypes[type];\n        if (dataType && dataType.onChange) return dataType.onChange.bind(this);\n        return noop;\n    },\n\n    // Run validation against the next complete set of model attributes,\n    // returning `true` if all is well. Otherwise, fire an `\"invalid\"` event.\n    _validate: function (attrs, options) {\n        if (!options.validate || !this.validate) return true;\n        attrs = assign({}, this.attributes, attrs);\n        var error = this.validationError = this.validate(attrs, options) || null;\n        if (!error) return true;\n        this.trigger('invalid', this, error, assign(options || {}, {validationError: error}));\n        return false;\n    },\n\n    _createPropertyDefinition: function (name, desc, isSession) {\n        return createPropertyDefinition(this, name, desc, isSession);\n    },\n\n    // just makes friendlier errors when trying to define a new model\n    // only used when setting up original property definitions\n    _ensureValidType: function (type) {\n        return includes(['string', 'number', 'boolean', 'array', 'object', 'date', 'state', 'any']\n            .concat(Object.keys(this._dataTypes)), type) ? type : undefined;\n    },\n\n    getAttributes: function (options, raw) {\n        options = assign({\n            session: false,\n            props: false,\n            derived: false\n        }, options || {});\n        var res = {};\n        var val, def;\n        for (var item in this._definition) {\n            def = this._definition[item];\n            if ((options.session && def.session) || (options.props && !def.session)) {\n                val = raw ? this._values[item] : this[item];\n                if (raw && val && isFunction(val.serialize)) val = val.serialize();\n                if (typeof val === 'undefined') val = result(def, 'default');\n                if (typeof val !== 'undefined') res[item] = val;\n            }\n        }\n        if (options.derived) {\n            for (var derivedItem in this._derived) res[derivedItem] = this[derivedItem];\n        }\n        return res;\n    },\n\n    _initDerived: function () {\n        var self = this;\n\n        forOwn(this._derived, function (value, name) {\n            var def = self._derived[name];\n            def.deps = def.depList;\n\n            var update = function () {\n                var newVal = def.fn.call(self);\n\n                if (self._cache[name] !== newVal || !def.cache) {\n                    if (def.cache) {\n                        self._previousAttributes[name] = self._cache[name];\n                    }\n                    self._cache[name] = newVal;\n                    self.trigger('change:' + name, self, self._cache[name]);\n                }\n            };\n\n            def.deps.forEach(function (propString) {\n                self._keyTree.add(propString, update);\n            });\n        });\n\n        this.on('all', function (eventName) {\n            if (changeRE.test(eventName)) {\n                self._keyTree.get(eventName.split(':')[1]).forEach(function (fn) {\n                    fn();\n                });\n            }\n        }, this);\n    },\n\n    _getDerivedProperty: function (name, flushCache) {\n        // is this a derived property that is cached\n        if (this._derived[name].cache) {\n            //set if this is the first time, or flushCache is set\n            if (flushCache || !this._cache.hasOwnProperty(name)) {\n                this._cache[name] = this._derived[name].fn.apply(this);\n            }\n            return this._cache[name];\n        } else {\n            return this._derived[name].fn.apply(this);\n        }\n    },\n\n    _initCollections: function () {\n        var coll;\n        if (!this._collections) return;\n        for (coll in this._collections) {\n            this._safeSet(coll, new this._collections[coll](null, {parent: this}));\n        }\n    },\n\n    _initChildren: function () {\n        var child;\n        if (!this._children) return;\n        for (child in this._children) {\n            this._safeSet(child, new this._children[child]({}, {parent: this}));\n            this.listenTo(this[child], 'all', this._getCachedEventBubblingHandler(child));\n        }\n    },\n\n    // Returns a bound handler for doing event bubbling while\n    // adding a name to the change string.\n    _getCachedEventBubblingHandler: function (propertyName) {\n        if (!this._eventBubblingHandlerCache[propertyName]) {\n            this._eventBubblingHandlerCache[propertyName] = function (name, model, newValue) {\n                if (changeRE.test(name)) {\n                    this.trigger('change:' + propertyName + '.' + name.split(':')[1], model, newValue);\n                } else if (name === 'change') {\n                    this.trigger('change', this);\n                }\n            }.bind(this);\n        }\n        return this._eventBubblingHandlerCache[propertyName];\n    },\n\n    // Check that all required attributes are present\n    _verifyRequired: function () {\n        var attrs = this.attributes; // should include session\n        for (var def in this._definition) {\n            if (this._definition[def].required && typeof attrs[def] === 'undefined') {\n                return false;\n            }\n        }\n        return true;\n    },\n\n    // expose safeSet method\n    _safeSet: function safeSet(property, value) {\n        if (property in this) {\n            throw new Error('Encountered namespace collision while setting instance property `' + property + '`');\n        }\n        this[property] = value;\n        return this;\n    }\n});\n\n// getter for attributes\nObject.defineProperties(Base.prototype, {\n    attributes: {\n        get: function () {\n            return this.getAttributes({props: true, session: true});\n        }\n    },\n    all: {\n        get: function () {\n            return this.getAttributes({\n                session: true,\n                props: true,\n                derived: true\n            });\n        }\n    },\n    isState: {\n        get: function () { return true; },\n        set: function () { }\n    }\n});\n\n// helper for creating/storing property definitions and creating\n// appropriate getters/setters\nfunction createPropertyDefinition(object, name, desc, isSession) {\n    var def = object._definition[name] = {};\n    var type, descArray;\n\n    if (isString(desc)) {\n        // grab our type if all we've got is a string\n        type = object._ensureValidType(desc);\n        if (type) def.type = type;\n    } else {\n        //Transform array of ['type', required, default] to object form\n        if (Array.isArray(desc)) {\n            descArray = desc;\n            desc = {\n                type: descArray[0],\n                required: descArray[1],\n                'default': descArray[2]\n            };\n        }\n\n        type = object._ensureValidType(desc.type);\n        if (type) def.type = type;\n\n        if (desc.required) def.required = true;\n\n        if (desc['default'] && typeof desc['default'] === 'object') {\n            throw new TypeError('The default value for ' + name + ' cannot be an object/array, must be a value or a function which returns a value/object/array');\n        }\n\n        def['default'] = desc['default'];\n\n        def.allowNull = desc.allowNull ? desc.allowNull : false;\n        if (desc.setOnce) def.setOnce = true;\n        if (def.required && def['default'] === undefined && !def.setOnce) def['default'] = object._getDefaultForType(type);\n        def.test = desc.test;\n        def.values = desc.values;\n    }\n    if (isSession) def.session = true;\n\n    if (!type) {\n        type = isString(desc) ? desc : desc.type;\n        // TODO: start throwing a TypeError in future major versions instead of warning\n        console.warn('Invalid data type of `' + type + '` for `' + name + '` property. Use one of the default types or define your own');\n    }\n\n    // define a getter/setter on the prototype\n    // but they get/set on the instance\n    Object.defineProperty(object, name, {\n        set: function (val) {\n            this.set(name, val);\n        },\n        get: function () {\n            if (!this._values) {\n                throw Error('You may be trying to `extend` a state object with \"' + name + '\" which has been defined in `props` on the object being extended');\n            }\n            var value = this._values[name];\n            var typeDef = this._dataTypes[def.type];\n            if (typeof value !== 'undefined') {\n                if (typeDef && typeDef.get) {\n                    value = typeDef.get(value);\n                }\n                return value;\n            }\n            var defaultValue = result(def, 'default');\n            this._values[name] = defaultValue;\n            // If we've set a defaultValue, fire a change handler effectively marking\n            // its change from undefined to the default value.\n            if (typeof defaultValue !== 'undefined') {\n                var onChange = this._getOnChangeForType(def.type);\n                onChange(defaultValue, value, name);\n            }\n            return defaultValue;\n        }\n    });\n\n    return def;\n}\n\n// helper for creating derived property definitions\nfunction createDerivedProperty(modelProto, name, definition) {\n    var def = modelProto._derived[name] = {\n        fn: isFunction(definition) ? definition : definition.fn,\n        cache: (definition.cache !== false),\n        depList: definition.deps || []\n    };\n\n    // add to our shared dependency list\n    def.depList.forEach(function (dep) {\n        modelProto._deps[dep] = union(modelProto._deps[dep] || [], [name]);\n    });\n\n    // defined a top-level getter for derived names\n    Object.defineProperty(modelProto, name, {\n        get: function () {\n            return this._getDerivedProperty(name);\n        },\n        set: function () {\n            throw new TypeError(\"`\" + name + \"` is a derived property, it can't be set directly.\");\n        }\n    });\n}\n\nvar dataTypes = {\n    string: {\n        'default': function () {\n            return '';\n        }\n    },\n    date: {\n        set: function (newVal) {\n            var newType;\n            if (newVal == null) {\n                newType = typeof null;\n            } else if (!isDate(newVal)) {\n                var err = null;\n                var dateVal = new Date(newVal).valueOf();\n                if (isNaN(dateVal)) {\n                    // If the newVal cant be parsed, then try parseInt first\n                    dateVal = new Date(parseInt(newVal, 10)).valueOf();\n                    if (isNaN(dateVal)) err = true;\n                }\n                newVal = dateVal;\n                newType = 'date';\n                if (err) {\n                    newType = typeof newVal;\n                }\n            } else {\n                newType = 'date';\n                newVal = newVal.valueOf();\n            }\n\n            return {\n                val: newVal,\n                type: newType\n            };\n        },\n        get: function (val) {\n            if (val == null) { return val; }\n            return new Date(val);\n        },\n        'default': function () {\n            return new Date();\n        }\n    },\n    array: {\n        set: function (newVal) {\n            return {\n                val: newVal,\n                type: Array.isArray(newVal) ? 'array' : typeof newVal\n            };\n        },\n        'default': function () {\n            return [];\n        }\n    },\n    object: {\n        set: function (newVal) {\n            var newType = typeof newVal;\n            // we have to have a way of supporting \"missing\" objects.\n            // Null is an object, but setting a value to undefined\n            // should work too, IMO. We just override it, in that case.\n            if (newType !== 'object' && newVal === undefined) {\n                newVal = null;\n                newType = 'object';\n            }\n            return {\n                val: newVal,\n                type: newType\n            };\n        },\n        'default': function () {\n            return {};\n        }\n    },\n    // the `state` data type is a bit special in that setting it should\n    // also bubble events\n    state: {\n        set: function (newVal) {\n            var isInstance = newVal instanceof Base || (newVal && newVal.isState);\n            if (isInstance) {\n                return {\n                    val: newVal,\n                    type: 'state'\n                };\n            } else {\n                return {\n                    val: newVal,\n                    type: typeof newVal\n                };\n            }\n        },\n        compare: function (currentVal, newVal) {\n            return currentVal === newVal;\n        },\n\n        onChange : function(newVal, previousVal, attributeName){\n            // if this has changed we want to also handle\n            // event propagation\n            if (previousVal) {\n                this.stopListening(previousVal, 'all', this._getCachedEventBubblingHandler(attributeName));\n            }\n\n            if (newVal != null) {\n                this.listenTo(newVal, 'all', this._getCachedEventBubblingHandler(attributeName));\n            }\n        }\n    }\n};\n\n// the extend method used to extend prototypes, maintain inheritance chains for instanceof\n// and allow for additions to the model definitions.\nfunction extend(protoProps) {\n    /*jshint validthis:true*/\n    var parent = this;\n    var child;\n\n    // The constructor function for the new subclass is either defined by you\n    // (the \"constructor\" property in your `extend` definition), or defaulted\n    // by us to simply call the parent's constructor.\n    if (protoProps && protoProps.hasOwnProperty('constructor')) {\n        child = protoProps.constructor;\n    } else {\n        child = function () {\n            return parent.apply(this, arguments);\n        };\n    }\n\n    // Add static properties to the constructor function from parent\n    assign(child, parent);\n\n    // Set the prototype chain to inherit from `parent`, without calling\n    // `parent`'s constructor function.\n    var Surrogate = function () { this.constructor = child; };\n    Surrogate.prototype = parent.prototype;\n    child.prototype = new Surrogate();\n\n    // set prototype level objects\n    child.prototype._derived =  assign({}, parent.prototype._derived);\n    child.prototype._deps = assign({}, parent.prototype._deps);\n    child.prototype._definition = assign({}, parent.prototype._definition);\n    child.prototype._collections = assign({}, parent.prototype._collections);\n    child.prototype._children = assign({}, parent.prototype._children);\n    child.prototype._dataTypes = assign({}, parent.prototype._dataTypes || dataTypes);\n\n    // Mix in all prototype properties to the subclass if supplied.\n    if (protoProps) {\n        var omitFromExtend = [\n            'dataTypes', 'props', 'session', 'derived', 'collections', 'children'\n        ];\n        for(var i = 0; i < arguments.length; i++) {\n            var def = arguments[i];\n            if (def.dataTypes) {\n                forOwn(def.dataTypes, function (def, name) {\n                    child.prototype._dataTypes[name] = def;\n                });\n            }\n            if (def.props) {\n                forOwn(def.props, function (def, name) {\n                    createPropertyDefinition(child.prototype, name, def);\n                });\n            }\n            if (def.session) {\n                forOwn(def.session, function (def, name) {\n                    createPropertyDefinition(child.prototype, name, def, true);\n                });\n            }\n            if (def.derived) {\n                forOwn(def.derived, function (def, name) {\n                    createDerivedProperty(child.prototype, name, def);\n                });\n            }\n            if (def.collections) {\n                forOwn(def.collections, function (constructor, name) {\n                    child.prototype._collections[name] = constructor;\n                });\n            }\n            if (def.children) {\n                forOwn(def.children, function (constructor, name) {\n                    child.prototype._children[name] = constructor;\n                });\n            }\n            assign(child.prototype, omit(def, omitFromExtend));\n        }\n    }\n\n    // Set a convenience property in case the parent's prototype is needed\n    // later.\n    child.__super__ = parent.prototype;\n\n    return child;\n}\n\nBase.extend = extend;\n\n// Our main exports\nmodule.exports = Base;\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWY0NS5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9hbXBlcnNhbmQtc3RhdGUvYW1wZXJzYW5kLXN0YXRlLmpzPzYzZDQiXSwic291cmNlc0NvbnRlbnQiOlsiJ3VzZSBzdHJpY3QnO1xuLyokQU1QRVJTQU5EX1ZFUlNJT04qL1xudmFyIHVuaXF1ZUlkID0gcmVxdWlyZSgnbG9kYXNoL3VuaXF1ZUlkJyk7XG52YXIgYXNzaWduID0gcmVxdWlyZSgnbG9kYXNoL2Fzc2lnbicpO1xudmFyIGNsb25lT2JqID0gZnVuY3Rpb24ob2JqKSB7IHJldHVybiBhc3NpZ24oe30sIG9iaik7IH07XG52YXIgb21pdCA9IHJlcXVpcmUoJ2xvZGFzaC9vbWl0Jyk7XG52YXIgZXNjYXBlID0gcmVxdWlyZSgnbG9kYXNoL2VzY2FwZScpO1xudmFyIGZvck93biA9IHJlcXVpcmUoJ2xvZGFzaC9mb3JPd24nKTtcbnZhciBpbmNsdWRlcyA9IHJlcXVpcmUoJ2xvZGFzaC9pbmNsdWRlcycpO1xudmFyIGlzU3RyaW5nID0gcmVxdWlyZSgnbG9kYXNoL2lzU3RyaW5nJyk7XG52YXIgaXNPYmplY3QgPSByZXF1aXJlKCdsb2Rhc2gvaXNPYmplY3QnKTtcbnZhciBpc0RhdGUgPSByZXF1aXJlKCdsb2Rhc2gvaXNEYXRlJyk7XG52YXIgaXNGdW5jdGlvbiA9IHJlcXVpcmUoJ2xvZGFzaC9pc0Z1bmN0aW9uJyk7XG52YXIgX2lzRXF1YWwgPSByZXF1aXJlKCdsb2Rhc2gvaXNFcXVhbCcpOyAvLyB0byBhdm9pZCBzaGFkb3dpbmdcbnZhciBoYXMgPSByZXF1aXJlKCdsb2Rhc2gvaGFzJyk7XG52YXIgcmVzdWx0ID0gcmVxdWlyZSgnbG9kYXNoL3Jlc3VsdCcpO1xudmFyIHVuaW9uID0gcmVxdWlyZSgnbG9kYXNoL3VuaW9uJyk7XG52YXIgRXZlbnRzID0gcmVxdWlyZSgnYW1wZXJzYW5kLWV2ZW50cycpO1xudmFyIEtleVRyZWUgPSByZXF1aXJlKCdrZXktdHJlZS1zdG9yZScpO1xudmFyIGFycmF5TmV4dCA9IHJlcXVpcmUoJ2FycmF5LW5leHQnKTtcbnZhciBjaGFuZ2VSRSA9IC9eY2hhbmdlOi87XG52YXIgbm9vcCA9IGZ1bmN0aW9uICgpIHt9O1xuXG5mdW5jdGlvbiBCYXNlKGF0dHJzLCBvcHRpb25zKSB7XG4gICAgb3B0aW9ucyB8fCAob3B0aW9ucyA9IHt9KTtcbiAgICB0aGlzLmNpZCB8fCAodGhpcy5jaWQgPSB1bmlxdWVJZCgnc3RhdGUnKSk7XG4gICAgdGhpcy5fZXZlbnRzID0ge307XG4gICAgdGhpcy5fdmFsdWVzID0ge307XG4gICAgdGhpcy5fZXZlbnRCdWJibGluZ0hhbmRsZXJDYWNoZSA9IHt9O1xuICAgIHRoaXMuX2RlZmluaXRpb24gPSBPYmplY3QuY3JlYXRlKHRoaXMuX2RlZmluaXRpb24pO1xuICAgIGlmIChvcHRpb25zLnBhcnNlKSBhdHRycyA9IHRoaXMucGFyc2UoYXR0cnMsIG9wdGlvbnMpO1xuICAgIHRoaXMucGFyZW50ID0gb3B0aW9ucy5wYXJlbnQ7XG4gICAgdGhpcy5jb2xsZWN0aW9uID0gb3B0aW9ucy5jb2xsZWN0aW9uO1xuICAgIHRoaXMuX2tleVRyZWUgPSBuZXcgS2V5VHJlZSgpO1xuICAgIHRoaXMuX2luaXRDb2xsZWN0aW9ucygpO1xuICAgIHRoaXMuX2luaXRDaGlsZHJlbigpO1xuICAgIHRoaXMuX2NhY2hlID0ge307XG4gICAgdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzID0ge307XG4gICAgaWYgKGF0dHJzKSB0aGlzLnNldChhdHRycywgYXNzaWduKHtzaWxlbnQ6IHRydWUsIGluaXRpYWw6IHRydWV9LCBvcHRpb25zKSk7XG4gICAgdGhpcy5fY2hhbmdlZCA9IHt9O1xuICAgIGlmICh0aGlzLl9kZXJpdmVkKSB0aGlzLl9pbml0RGVyaXZlZCgpO1xuICAgIGlmIChvcHRpb25zLmluaXQgIT09IGZhbHNlKSB0aGlzLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cblxuYXNzaWduKEJhc2UucHJvdG90eXBlLCBFdmVudHMsIHtcbiAgICAvLyBjYW4gYmUgYWxsb3csIGlnbm9yZSwgcmVqZWN0XG4gICAgZXh0cmFQcm9wZXJ0aWVzOiAnaWdub3JlJyxcblxuICAgIGlkQXR0cmlidXRlOiAnaWQnLFxuXG4gICAgbmFtZXNwYWNlQXR0cmlidXRlOiAnbmFtZXNwYWNlJyxcblxuICAgIHR5cGVBdHRyaWJ1dGU6ICdtb2RlbFR5cGUnLFxuXG4gICAgLy8gU3R1YmJlZCBvdXQgdG8gYmUgb3ZlcndyaXR0ZW5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICAvLyBHZXQgSUQgb2YgbW9kZWwgcGVyIGNvbmZpZ3VyYXRpb24uXG4gICAgLy8gU2hvdWxkICphbHdheXMqIGJlIGhvdyBJRCBpcyBkZXRlcm1pbmVkIGJ5IG90aGVyIGNvZGUuXG4gICAgZ2V0SWQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXNbdGhpcy5pZEF0dHJpYnV0ZV07XG4gICAgfSxcblxuICAgIC8vIEdldCBuYW1lc3BhY2Ugb2YgbW9kZWwgcGVyIGNvbmZpZ3VyYXRpb24uXG4gICAgLy8gU2hvdWxkICphbHdheXMqIGJlIGhvdyBuYW1lc3BhY2UgaXMgZGV0ZXJtaW5lZCBieSBvdGhlciBjb2RlLlxuICAgIGdldE5hbWVzcGFjZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpc1t0aGlzLm5hbWVzcGFjZUF0dHJpYnV0ZV07XG4gICAgfSxcblxuICAgIC8vIEdldCB0eXBlIG9mIG1vZGVsIHBlciBjb25maWd1cmF0aW9uLlxuICAgIC8vIFNob3VsZCAqYWx3YXlzKiBiZSBob3cgdHlwZSBpcyBkZXRlcm1pbmVkIGJ5IG90aGVyIGNvZGUuXG4gICAgZ2V0VHlwZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpc1t0aGlzLnR5cGVBdHRyaWJ1dGVdO1xuICAgIH0sXG5cbiAgICAvLyBBIG1vZGVsIGlzIG5ldyBpZiBpdCBoYXMgbmV2ZXIgYmVlbiBzYXZlZCB0byB0aGUgc2VydmVyLCBhbmQgbGFja3MgYW4gaWQuXG4gICAgaXNOZXc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0SWQoKSA9PSBudWxsO1xuICAgIH0sXG5cbiAgICAvLyBnZXQgSFRNTC1lc2NhcGVkIHZhbHVlIG9mIGF0dHJpYnV0ZVxuICAgIGVzY2FwZTogZnVuY3Rpb24gKGF0dHIpIHtcbiAgICAgICAgcmV0dXJuIGVzY2FwZSh0aGlzLmdldChhdHRyKSk7XG4gICAgfSxcblxuICAgIC8vIENoZWNrIGlmIHRoZSBtb2RlbCBpcyBjdXJyZW50bHkgaW4gYSB2YWxpZCBzdGF0ZS5cbiAgICBpc1ZhbGlkOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5fdmFsaWRhdGUoe30sIGFzc2lnbihvcHRpb25zIHx8IHt9LCB7IHZhbGlkYXRlOiB0cnVlIH0pKTtcbiAgICB9LFxuXG4gICAgLy8gUGFyc2UgY2FuIGJlIHVzZWQgcmVtYXAvcmVzdHJ1Y3R1cmUvcmVuYW1lIGluY29taW5nIHByb3BlcnRpZXNcbiAgICAvLyBiZWZvcmUgdGhleSBhcmUgYXBwbGllZCB0byBhdHRyaWJ1dGVzLlxuICAgIHBhcnNlOiBmdW5jdGlvbiAocmVzcCwgb3B0aW9ucykge1xuICAgICAgICAvL2pzaGludCB1bnVzZWQ6ZmFsc2VcbiAgICAgICAgcmV0dXJuIHJlc3A7XG4gICAgfSxcblxuICAgIC8vIFNlcmlhbGl6ZSBpcyB0aGUgaW52ZXJzZSBvZiBgcGFyc2VgIGl0IGxldHMgeW91IG1hc3NhZ2UgZGF0YVxuICAgIC8vIG9uIHRoZSB3YXkgb3V0LiBCZWZvcmUsIHNlbmRpbmcgdG8gc2VydmVyLCBmb3IgZXhhbXBsZS5cbiAgICBzZXJpYWxpemU6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBhdHRyT3B0cyA9IGFzc2lnbih7cHJvcHM6IHRydWV9LCBvcHRpb25zKTtcbiAgICAgICAgdmFyIHJlcyA9IHRoaXMuZ2V0QXR0cmlidXRlcyhhdHRyT3B0cywgdHJ1ZSk7XG4gICAgICAgIFxuICAgICAgICB2YXIgc2V0RnJvbVNlcmlhbGl6ZWRWYWx1ZSA9IGZ1bmN0aW9uICh2YWx1ZSwga2V5KSB7XG5cdCAgICAgICAgcmVzW2tleV0gPSB0aGlzW2tleV0uc2VyaWFsaXplKCk7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcbiAgICAgICAgXG4gICAgICAgIGZvck93bih0aGlzLl9jaGlsZHJlbiwgc2V0RnJvbVNlcmlhbGl6ZWRWYWx1ZSk7XG4gICAgICAgIGZvck93bih0aGlzLl9jb2xsZWN0aW9ucywgc2V0RnJvbVNlcmlhbGl6ZWRWYWx1ZSk7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfSxcblxuICAgIC8vIE1haW4gc2V0IG1ldGhvZCB1c2VkIGJ5IGdlbmVyYXRlZCBzZXR0ZXJzL2dldHRlcnMgYW5kIGNhblxuICAgIC8vIGJlIHVzZWQgZGlyZWN0bHkgaWYgeW91IG5lZWQgdG8gcGFzcyBvcHRpb25zIG9yIHNldCBtdWx0aXBsZVxuICAgIC8vIHByb3BlcnRpZXMgYXQgb25jZS5cbiAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgdmFyIGV4dHJhUHJvcGVydGllcyA9IHRoaXMuZXh0cmFQcm9wZXJ0aWVzO1xuICAgICAgICB2YXIgd2FzQ2hhbmdpbmcsIGNoYW5nZUV2ZW50cywgbmV3VHlwZSwgbmV3VmFsLCBkZWYsIGNhc3QsIGVyciwgYXR0cixcbiAgICAgICAgICAgIGF0dHJzLCBkYXRhVHlwZSwgc2lsZW50LCB1bnNldCwgY3VycmVudFZhbCwgaW5pdGlhbCwgaGFzQ2hhbmdlZCwgaXNFcXVhbCwgb25DaGFuZ2U7XG5cbiAgICAgICAgLy8gSGFuZGxlIGJvdGggYFwia2V5XCIsIHZhbHVlYCBhbmQgYHtrZXk6IHZhbHVlfWAgLXN0eWxlIGFyZ3VtZW50cy5cbiAgICAgICAgaWYgKGlzT2JqZWN0KGtleSkgfHwga2V5ID09PSBudWxsKSB7XG4gICAgICAgICAgICBhdHRycyA9IGtleTtcbiAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGF0dHJzID0ge307XG4gICAgICAgICAgICBhdHRyc1trZXldID0gdmFsdWU7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICBpZiAoIXRoaXMuX3ZhbGlkYXRlKGF0dHJzLCBvcHRpb25zKSkgcmV0dXJuIGZhbHNlO1xuXG4gICAgICAgIC8vIEV4dHJhY3QgYXR0cmlidXRlcyBhbmQgb3B0aW9ucy5cbiAgICAgICAgdW5zZXQgPSBvcHRpb25zLnVuc2V0O1xuICAgICAgICBzaWxlbnQgPSBvcHRpb25zLnNpbGVudDtcbiAgICAgICAgaW5pdGlhbCA9IG9wdGlvbnMuaW5pdGlhbDtcblxuICAgICAgICAvLyBJbml0aWFsaXplIGNoYW5nZSB0cmFja2luZy5cbiAgICAgICAgd2FzQ2hhbmdpbmcgPSB0aGlzLl9jaGFuZ2luZztcbiAgICAgICAgdGhpcy5fY2hhbmdpbmcgPSB0cnVlO1xuICAgICAgICBjaGFuZ2VFdmVudHMgPSBbXTtcblxuICAgICAgICAvLyBpZiBub3QgYWxyZWFkeSBjaGFuZ2luZywgc3RvcmUgcHJldmlvdXNcbiAgICAgICAgaWYgKGluaXRpYWwpIHtcbiAgICAgICAgICAgIHRoaXMuX3ByZXZpb3VzQXR0cmlidXRlcyA9IHt9O1xuICAgICAgICB9IGVsc2UgaWYgKCF3YXNDaGFuZ2luZykge1xuICAgICAgICAgICAgdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzID0gdGhpcy5hdHRyaWJ1dGVzO1xuICAgICAgICAgICAgdGhpcy5fY2hhbmdlZCA9IHt9O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRm9yIGVhY2ggYHNldGAgYXR0cmlidXRlLi4uXG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBrZXlzID0gT2JqZWN0LmtleXMoYXR0cnMpLCBsZW4gPSBrZXlzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgICAgICBhdHRyID0ga2V5c1tpXTtcbiAgICAgICAgICAgIG5ld1ZhbCA9IGF0dHJzW2F0dHJdO1xuICAgICAgICAgICAgbmV3VHlwZSA9IHR5cGVvZiBuZXdWYWw7XG4gICAgICAgICAgICBjdXJyZW50VmFsID0gdGhpcy5fdmFsdWVzW2F0dHJdO1xuICAgICAgICAgICAgZGVmID0gdGhpcy5fZGVmaW5pdGlvblthdHRyXTtcblxuICAgICAgICAgICAgaWYgKCFkZWYpIHtcbiAgICAgICAgICAgICAgICAvLyBpZiB0aGlzIGlzIGEgY2hpbGQgbW9kZWwgb3IgY29sbGVjdGlvblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLl9jaGlsZHJlblthdHRyXSB8fCB0aGlzLl9jb2xsZWN0aW9uc1thdHRyXSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWlzT2JqZWN0KG5ld1ZhbCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5ld1ZhbCA9IHt9O1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpc1thdHRyXS5zZXQobmV3VmFsLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChleHRyYVByb3BlcnRpZXMgPT09ICdpZ25vcmUnKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoZXh0cmFQcm9wZXJ0aWVzID09PSAncmVqZWN0Jykge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdObyBcIicgKyBhdHRyICsgJ1wiIHByb3BlcnR5IGRlZmluZWQgb24gJyArICh0aGlzLnR5cGUgfHwgJ3RoaXMnKSArICcgbW9kZWwgYW5kIGV4dHJhUHJvcGVydGllcyBub3Qgc2V0IHRvIFwiaWdub3JlXCIgb3IgXCJhbGxvd1wiJyk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChleHRyYVByb3BlcnRpZXMgPT09ICdhbGxvdycpIHtcbiAgICAgICAgICAgICAgICAgICAgZGVmID0gdGhpcy5fY3JlYXRlUHJvcGVydHlEZWZpbml0aW9uKGF0dHIsICdhbnknKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGV4dHJhUHJvcGVydGllcykge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdJbnZhbGlkIHZhbHVlIGZvciBleHRyYVByb3BlcnRpZXM6IFwiJyArIGV4dHJhUHJvcGVydGllcyArICdcIicpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaXNFcXVhbCA9IHRoaXMuX2dldENvbXBhcmVGb3JUeXBlKGRlZi50eXBlKTtcbiAgICAgICAgICAgIG9uQ2hhbmdlID0gdGhpcy5fZ2V0T25DaGFuZ2VGb3JUeXBlKGRlZi50eXBlKTtcbiAgICAgICAgICAgIGRhdGFUeXBlID0gdGhpcy5fZGF0YVR5cGVzW2RlZi50eXBlXTtcblxuICAgICAgICAgICAgLy8gY2hlY2sgdHlwZSBpZiB3ZSBoYXZlIG9uZVxuICAgICAgICAgICAgaWYgKGRhdGFUeXBlICYmIGRhdGFUeXBlLnNldCkge1xuICAgICAgICAgICAgICAgIGNhc3QgPSBkYXRhVHlwZS5zZXQobmV3VmFsKTtcbiAgICAgICAgICAgICAgICBuZXdWYWwgPSBjYXN0LnZhbDtcbiAgICAgICAgICAgICAgICBuZXdUeXBlID0gY2FzdC50eXBlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBJZiB3ZSd2ZSBkZWZpbmVkIGEgdGVzdCwgcnVuIGl0XG4gICAgICAgICAgICBpZiAoZGVmLnRlc3QpIHtcbiAgICAgICAgICAgICAgICBlcnIgPSBkZWYudGVzdC5jYWxsKHRoaXMsIG5ld1ZhbCwgbmV3VHlwZSk7XG4gICAgICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdQcm9wZXJ0eSBcXCcnICsgYXR0ciArICdcXCcgZmFpbGVkIHZhbGlkYXRpb24gd2l0aCBlcnJvcjogJyArIGVycik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBJZiB3ZSBhcmUgcmVxdWlyZWQgYnV0IHVuZGVmaW5lZCwgdGhyb3cgZXJyb3IuXG4gICAgICAgICAgICAvLyBJZiB3ZSBhcmUgbnVsbCBhbmQgYXJlIG5vdCBhbGxvd2luZyBudWxsLCB0aHJvdyBlcnJvclxuICAgICAgICAgICAgLy8gSWYgd2UgaGF2ZSBhIGRlZmluZWQgdHlwZSBhbmQgdGhlIG5ldyB0eXBlIGRvZXNuJ3QgbWF0Y2gsIGFuZCB3ZSBhcmUgbm90IG51bGwsIHRocm93IGVycm9yLlxuICAgICAgICAgICAgLy8gSWYgd2UgcmVxdWlyZSBzcGVjaWZpYyB2YWx1ZSBhbmQgbmV3IG9uZSBpcyBub3Qgb25lIG9mIHRoZW0sIHRocm93IGVycm9yICh1bmxlc3MgaXQgaGFzIGRlZmF1bHQgdmFsdWUgb3Igd2UncmUgdW5zZXR0aW5nIGl0IHdpdGggdW5kZWZpbmVkKS5cblxuICAgICAgICAgICAgaWYgKG5ld1ZhbCA9PT0gdW5kZWZpbmVkICYmIGRlZi5yZXF1aXJlZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1JlcXVpcmVkIHByb3BlcnR5IFxcJycgKyBhdHRyICsgJ1xcJyBtdXN0IGJlIG9mIHR5cGUgJyArIGRlZi50eXBlICsgJy4gVHJpZWQgdG8gc2V0ICcgKyBuZXdWYWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG5ld1ZhbCA9PT0gbnVsbCAmJiBkZWYucmVxdWlyZWQgJiYgIWRlZi5hbGxvd051bGwpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdQcm9wZXJ0eSBcXCcnICsgYXR0ciArICdcXCcgbXVzdCBiZSBvZiB0eXBlICcgKyBkZWYudHlwZSArICcgKGNhbm5vdCBiZSBudWxsKS4gVHJpZWQgdG8gc2V0ICcgKyBuZXdWYWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKChkZWYudHlwZSAmJiBkZWYudHlwZSAhPT0gJ2FueScgJiYgZGVmLnR5cGUgIT09IG5ld1R5cGUpICYmIG5ld1ZhbCAhPT0gbnVsbCAmJiBuZXdWYWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Byb3BlcnR5IFxcJycgKyBhdHRyICsgJ1xcJyBtdXN0IGJlIG9mIHR5cGUgJyArIGRlZi50eXBlICsgJy4gVHJpZWQgdG8gc2V0ICcgKyBuZXdWYWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRlZi52YWx1ZXMgJiYgIWluY2x1ZGVzKGRlZi52YWx1ZXMsIG5ld1ZhbCkpIHtcbiAgICAgICAgICAgICAgICB2YXIgZGVmYXVsdFZhbHVlID0gcmVzdWx0KGRlZiwgJ2RlZmF1bHQnKTtcbiAgICAgICAgICAgICAgICBpZiAodW5zZXQgJiYgZGVmYXVsdFZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgbmV3VmFsID0gZGVmYXVsdFZhbHVlO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoIXVuc2V0IHx8ICh1bnNldCAmJiBuZXdWYWwgIT09IHVuZGVmaW5lZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignUHJvcGVydHkgXFwnJyArIGF0dHIgKyAnXFwnIG11c3QgYmUgb25lIG9mIHZhbHVlczogJyArIGRlZi52YWx1ZXMuam9pbignLCAnKSArICcuIFRyaWVkIHRvIHNldCAnICsgbmV3VmFsKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFdlIGtub3cgdGhpcyBoYXMgJ2NoYW5nZWQnIGlmIGl0J3MgdGhlIGluaXRpYWwgc2V0LCBzbyBza2lwIGEgcG90ZW50aWFsbHkgZXhwZW5zaXZlIGlzRXF1YWwgY2hlY2suXG4gICAgICAgICAgICBoYXNDaGFuZ2VkID0gaW5pdGlhbCB8fCAhaXNFcXVhbChjdXJyZW50VmFsLCBuZXdWYWwsIGF0dHIpO1xuXG4gICAgICAgICAgICAvLyBlbmZvcmNlIGBzZXRPbmNlYCBmb3IgcHJvcGVydGllcyBpZiBzZXRcbiAgICAgICAgICAgIGlmIChkZWYuc2V0T25jZSAmJiBjdXJyZW50VmFsICE9PSB1bmRlZmluZWQgJiYgaGFzQ2hhbmdlZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Byb3BlcnR5IFxcJycgKyBhdHRyICsgJ1xcJyBjYW4gb25seSBiZSBzZXQgb25jZS4nKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gc2V0L3Vuc2V0IGF0dHJpYnV0ZXMuXG4gICAgICAgICAgICAvLyBJZiB0aGlzIGlzIG5vdCB0aGUgaW5pdGlhbCBzZXQsIGtlZXAgdHJhY2sgb2YgY2hhbmdlZCBhdHRyaWJ1dGVzXG4gICAgICAgICAgICAvLyBhbmQgcHVzaCB0byBjaGFuZ2VFdmVudHMgYXJyYXkgc28gd2UgY2FuIGZpcmUgZXZlbnRzLlxuICAgICAgICAgICAgaWYgKGhhc0NoYW5nZWQpIHtcblxuICAgICAgICAgICAgICAgIC8vIFRoaXMgZmlyZXMgbm8gbWF0dGVyIHdoYXQsIGV2ZW4gb24gaW5pdGlhbCBzZXQuXG4gICAgICAgICAgICAgICAgb25DaGFuZ2UobmV3VmFsLCBjdXJyZW50VmFsLCBhdHRyKTtcblxuICAgICAgICAgICAgICAgIC8vIElmIHRoaXMgaXMgYSBjaGFuZ2UgKG5vdCBhbiBpbml0aWFsIHNldCksIG1hcmsgdGhlIGNoYW5nZS5cbiAgICAgICAgICAgICAgICAvLyBOb3RlIGl0J3MgaW1wb3NzaWJsZSB0byB1bnNldCBvbiB0aGUgaW5pdGlhbCBzZXQgKGl0IHdpbGwgYWxyZWFkeSBiZSB1bnNldCksXG4gICAgICAgICAgICAgICAgLy8gc28gd2Ugb25seSBpbmNsdWRlIHRoYXQgbG9naWMgaGVyZS5cbiAgICAgICAgICAgICAgICBpZiAoIWluaXRpYWwpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fY2hhbmdlZFthdHRyXSA9IG5ld1ZhbDtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzW2F0dHJdID0gY3VycmVudFZhbDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHVuc2V0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBGSVhNRSBkZWxldGUgaXMgdmVyeSBzbG93LiBDYW4gd2UgZ2V0IGF3YXkgd2l0aCBzZXR0aW5nIHRvIHVuZGVmaW5lZD9cbiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLl92YWx1ZXNbYXR0cl07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFzaWxlbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNoYW5nZUV2ZW50cy5wdXNoKHtwcmV2OiBjdXJyZW50VmFsLCB2YWw6IG5ld1ZhbCwga2V5OiBhdHRyfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCF1bnNldCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl92YWx1ZXNbYXR0cl0gPSBuZXdWYWw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBOb3QgY2hhbmdlZFxuICAgICAgICAgICAgICAgIC8vIEZJWE1FIGRlbGV0ZSBpcyB2ZXJ5IHNsb3cuIENhbiB3ZSBnZXQgYXdheSB3aXRoIHNldHRpbmcgdG8gdW5kZWZpbmVkP1xuICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLl9jaGFuZ2VkW2F0dHJdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gRmlyZSBldmVudHMuIFRoaXMgYXJyYXkgaXMgbm90IHBvcHVsYXRlZCBpZiB3ZSBhcmUgdG9sZCB0byBiZSBzaWxlbnQuXG4gICAgICAgIGlmIChjaGFuZ2VFdmVudHMubGVuZ3RoKSB0aGlzLl9wZW5kaW5nID0gdHJ1ZTtcbiAgICAgICAgY2hhbmdlRXZlbnRzLmZvckVhY2goZnVuY3Rpb24gKGNoYW5nZSkge1xuICAgICAgICAgICAgc2VsZi50cmlnZ2VyKCdjaGFuZ2U6JyArIGNoYW5nZS5rZXksIHNlbGYsIGNoYW5nZS52YWwsIG9wdGlvbnMpO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBZb3UgbWlnaHQgYmUgd29uZGVyaW5nIHdoeSB0aGVyZSdzIGEgYHdoaWxlYCBsb29wIGhlcmUuIENoYW5nZXMgY2FuXG4gICAgICAgIC8vIGJlIHJlY3Vyc2l2ZWx5IG5lc3RlZCB3aXRoaW4gYFwiY2hhbmdlXCJgIGV2ZW50cy5cbiAgICAgICAgaWYgKHdhc0NoYW5naW5nKSByZXR1cm4gdGhpcztcbiAgICAgICAgd2hpbGUgKHRoaXMuX3BlbmRpbmcpIHtcbiAgICAgICAgICAgIHRoaXMuX3BlbmRpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMudHJpZ2dlcignY2hhbmdlJywgdGhpcywgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fcGVuZGluZyA9IGZhbHNlO1xuICAgICAgICB0aGlzLl9jaGFuZ2luZyA9IGZhbHNlO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuXG4gICAgZ2V0OiBmdW5jdGlvbiAoYXR0cikge1xuICAgICAgICByZXR1cm4gdGhpc1thdHRyXTtcbiAgICB9LFxuXG4gICAgLy8gVG9nZ2xlIGJvb2xlYW4gcHJvcGVydGllcyBvciBwcm9wZXJ0aWVzIHRoYXQgaGF2ZSBhIGB2YWx1ZXNgXG4gICAgLy8gYXJyYXkgaW4gaXRzIGRlZmluaXRpb24uXG4gICAgdG9nZ2xlOiBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgdmFyIGRlZiA9IHRoaXMuX2RlZmluaXRpb25bcHJvcGVydHldO1xuICAgICAgICBpZiAoZGVmLnR5cGUgPT09ICdib29sZWFuJykge1xuICAgICAgICAgICAgLy8gaWYgaXQncyBhIGJvb2wsIGp1c3QgZmxpcCBpdFxuICAgICAgICAgICAgdGhpc1twcm9wZXJ0eV0gPSAhdGhpc1twcm9wZXJ0eV07XG4gICAgICAgIH0gZWxzZSBpZiAoZGVmICYmIGRlZi52YWx1ZXMpIHtcbiAgICAgICAgICAgIC8vIElmIGl0J3MgYSBwcm9wZXJ0eSB3aXRoIGFuIGFycmF5IG9mIHZhbHVlc1xuICAgICAgICAgICAgLy8gc2tpcCB0byB0aGUgbmV4dCBvbmUgbG9vcGluZyBiYWNrIGlmIGF0IGVuZC5cbiAgICAgICAgICAgIHRoaXNbcHJvcGVydHldID0gYXJyYXlOZXh0KGRlZi52YWx1ZXMsIHRoaXNbcHJvcGVydHldKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0NhbiBvbmx5IHRvZ2dsZSBwcm9wZXJ0aWVzIHRoYXQgYXJlIHR5cGUgYGJvb2xlYW5gIG9yIGhhdmUgYHZhbHVlc2AgYXJyYXkuJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIC8vIEdldCBhbGwgb2YgdGhlIGF0dHJpYnV0ZXMgb2YgdGhlIG1vZGVsIGF0IHRoZSB0aW1lIG9mIHRoZSBwcmV2aW91c1xuICAgIC8vIGBcImNoYW5nZVwiYCBldmVudC5cbiAgICBwcmV2aW91c0F0dHJpYnV0ZXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGNsb25lT2JqKHRoaXMuX3ByZXZpb3VzQXR0cmlidXRlcyk7XG4gICAgfSxcblxuICAgIC8vIERldGVybWluZSBpZiB0aGUgbW9kZWwgaGFzIGNoYW5nZWQgc2luY2UgdGhlIGxhc3QgYFwiY2hhbmdlXCJgIGV2ZW50LlxuICAgIC8vIElmIHlvdSBzcGVjaWZ5IGFuIGF0dHJpYnV0ZSBuYW1lLCBkZXRlcm1pbmUgaWYgdGhhdCBhdHRyaWJ1dGUgaGFzIGNoYW5nZWQuXG4gICAgaGFzQ2hhbmdlZDogZnVuY3Rpb24gKGF0dHIpIHtcbiAgICAgICAgaWYgKGF0dHIgPT0gbnVsbCkgcmV0dXJuICEhT2JqZWN0LmtleXModGhpcy5fY2hhbmdlZCkubGVuZ3RoO1xuICAgICAgICBpZiAoaGFzKHRoaXMuX2Rlcml2ZWQsIGF0dHIpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fZGVyaXZlZFthdHRyXS5kZXBMaXN0LnNvbWUoZnVuY3Rpb24gKGRlcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmhhc0NoYW5nZWQoZGVwKTtcbiAgICAgICAgICAgIH0sIHRoaXMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBoYXModGhpcy5fY2hhbmdlZCwgYXR0cik7XG4gICAgfSxcblxuICAgIC8vIFJldHVybiBhbiBvYmplY3QgY29udGFpbmluZyBhbGwgdGhlIGF0dHJpYnV0ZXMgdGhhdCBoYXZlIGNoYW5nZWQsIG9yXG4gICAgLy8gZmFsc2UgaWYgdGhlcmUgYXJlIG5vIGNoYW5nZWQgYXR0cmlidXRlcy4gVXNlZnVsIGZvciBkZXRlcm1pbmluZyB3aGF0XG4gICAgLy8gcGFydHMgb2YgYSB2aWV3IG5lZWQgdG8gYmUgdXBkYXRlZCBhbmQvb3Igd2hhdCBhdHRyaWJ1dGVzIG5lZWQgdG8gYmVcbiAgICAvLyBwZXJzaXN0ZWQgdG8gdGhlIHNlcnZlci4gVW5zZXQgYXR0cmlidXRlcyB3aWxsIGJlIHNldCB0byB1bmRlZmluZWQuXG4gICAgLy8gWW91IGNhbiBhbHNvIHBhc3MgYW4gYXR0cmlidXRlcyBvYmplY3QgdG8gZGlmZiBhZ2FpbnN0IHRoZSBtb2RlbCxcbiAgICAvLyBkZXRlcm1pbmluZyBpZiB0aGVyZSAqd291bGQgYmUqIGEgY2hhbmdlLlxuICAgIGNoYW5nZWRBdHRyaWJ1dGVzOiBmdW5jdGlvbiAoZGlmZikge1xuICAgICAgICBpZiAoIWRpZmYpIHJldHVybiB0aGlzLmhhc0NoYW5nZWQoKSA/IGNsb25lT2JqKHRoaXMuX2NoYW5nZWQpIDogZmFsc2U7XG4gICAgICAgIHZhciB2YWwsIGNoYW5nZWQgPSBmYWxzZTtcbiAgICAgICAgdmFyIG9sZCA9IHRoaXMuX2NoYW5naW5nID8gdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzIDogdGhpcy5hdHRyaWJ1dGVzO1xuICAgICAgICB2YXIgZGVmLCBpc0VxdWFsO1xuICAgICAgICBmb3IgKHZhciBhdHRyIGluIGRpZmYpIHtcbiAgICAgICAgICAgIGRlZiA9IHRoaXMuX2RlZmluaXRpb25bYXR0cl07XG4gICAgICAgICAgICBpZiAoIWRlZikgY29udGludWU7XG4gICAgICAgICAgICBpc0VxdWFsID0gdGhpcy5fZ2V0Q29tcGFyZUZvclR5cGUoZGVmLnR5cGUpO1xuICAgICAgICAgICAgaWYgKGlzRXF1YWwob2xkW2F0dHJdLCAodmFsID0gZGlmZlthdHRyXSkpKSBjb250aW51ZTtcbiAgICAgICAgICAgIChjaGFuZ2VkIHx8IChjaGFuZ2VkID0ge30pKVthdHRyXSA9IHZhbDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY2hhbmdlZDtcbiAgICB9LFxuXG4gICAgdG9KU09OOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlcmlhbGl6ZSgpO1xuICAgIH0sXG5cbiAgICB1bnNldDogZnVuY3Rpb24gKGF0dHJzLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgYXR0cnMgPSBBcnJheS5pc0FycmF5KGF0dHJzKSA/IGF0dHJzIDogW2F0dHJzXTtcbiAgICAgICAgYXR0cnMuZm9yRWFjaChmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICB2YXIgZGVmID0gc2VsZi5fZGVmaW5pdGlvbltrZXldO1xuICAgICAgICAgICAgaWYgKCFkZWYpIHJldHVybjtcbiAgICAgICAgICAgIHZhciB2YWw7XG4gICAgICAgICAgICBpZiAoZGVmLnJlcXVpcmVkKSB7XG4gICAgICAgICAgICAgICAgdmFsID0gcmVzdWx0KGRlZiwgJ2RlZmF1bHQnKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gc2VsZi5zZXQoa2V5LCB2YWwsIG9wdGlvbnMpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc2VsZi5zZXQoa2V5LCB2YWwsIGFzc2lnbih7fSwgb3B0aW9ucywge3Vuc2V0OiB0cnVlfSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgY2xlYXI6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgT2JqZWN0LmtleXModGhpcy5hdHRyaWJ1dGVzKS5mb3JFYWNoKGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHNlbGYudW5zZXQoa2V5LCBvcHRpb25zKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICBwcmV2aW91czogZnVuY3Rpb24gKGF0dHIpIHtcbiAgICAgICAgaWYgKGF0dHIgPT0gbnVsbCB8fCAhT2JqZWN0LmtleXModGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzKS5sZW5ndGgpIHJldHVybiBudWxsO1xuICAgICAgICByZXR1cm4gdGhpcy5fcHJldmlvdXNBdHRyaWJ1dGVzW2F0dHJdO1xuICAgIH0sXG5cbiAgICAvLyBHZXQgZGVmYXVsdCB2YWx1ZXMgZm9yIGEgY2VydGFpbiB0eXBlXG4gICAgX2dldERlZmF1bHRGb3JUeXBlOiBmdW5jdGlvbiAodHlwZSkge1xuICAgICAgICB2YXIgZGF0YVR5cGUgPSB0aGlzLl9kYXRhVHlwZXNbdHlwZV07XG4gICAgICAgIHJldHVybiBkYXRhVHlwZSAmJiBkYXRhVHlwZVsnZGVmYXVsdCddO1xuICAgIH0sXG5cbiAgICAvLyBEZXRlcm1pbmUgd2hpY2ggY29tcGFyaXNvbiBhbGdvcml0aG0gdG8gdXNlIGZvciBjb21wYXJpbmcgYSBwcm9wZXJ0eVxuICAgIF9nZXRDb21wYXJlRm9yVHlwZTogZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgICAgdmFyIGRhdGFUeXBlID0gdGhpcy5fZGF0YVR5cGVzW3R5cGVdO1xuICAgICAgICBpZiAoZGF0YVR5cGUgJiYgZGF0YVR5cGUuY29tcGFyZSkgcmV0dXJuIGRhdGFUeXBlLmNvbXBhcmUuYmluZCh0aGlzKTtcbiAgICAgICAgcmV0dXJuIF9pc0VxdWFsOyAvLyBpZiBubyBjb21wYXJlIGZ1bmN0aW9uIGlzIGRlZmluZWQsIHVzZSBfLmlzRXF1YWxcbiAgICB9LFxuXG4gICAgX2dldE9uQ2hhbmdlRm9yVHlwZSA6IGZ1bmN0aW9uKHR5cGUpe1xuICAgICAgICB2YXIgZGF0YVR5cGUgPSB0aGlzLl9kYXRhVHlwZXNbdHlwZV07XG4gICAgICAgIGlmIChkYXRhVHlwZSAmJiBkYXRhVHlwZS5vbkNoYW5nZSkgcmV0dXJuIGRhdGFUeXBlLm9uQ2hhbmdlLmJpbmQodGhpcyk7XG4gICAgICAgIHJldHVybiBub29wO1xuICAgIH0sXG5cbiAgICAvLyBSdW4gdmFsaWRhdGlvbiBhZ2FpbnN0IHRoZSBuZXh0IGNvbXBsZXRlIHNldCBvZiBtb2RlbCBhdHRyaWJ1dGVzLFxuICAgIC8vIHJldHVybmluZyBgdHJ1ZWAgaWYgYWxsIGlzIHdlbGwuIE90aGVyd2lzZSwgZmlyZSBhbiBgXCJpbnZhbGlkXCJgIGV2ZW50LlxuICAgIF92YWxpZGF0ZTogZnVuY3Rpb24gKGF0dHJzLCBvcHRpb25zKSB7XG4gICAgICAgIGlmICghb3B0aW9ucy52YWxpZGF0ZSB8fCAhdGhpcy52YWxpZGF0ZSkgcmV0dXJuIHRydWU7XG4gICAgICAgIGF0dHJzID0gYXNzaWduKHt9LCB0aGlzLmF0dHJpYnV0ZXMsIGF0dHJzKTtcbiAgICAgICAgdmFyIGVycm9yID0gdGhpcy52YWxpZGF0aW9uRXJyb3IgPSB0aGlzLnZhbGlkYXRlKGF0dHJzLCBvcHRpb25zKSB8fCBudWxsO1xuICAgICAgICBpZiAoIWVycm9yKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgdGhpcy50cmlnZ2VyKCdpbnZhbGlkJywgdGhpcywgZXJyb3IsIGFzc2lnbihvcHRpb25zIHx8IHt9LCB7dmFsaWRhdGlvbkVycm9yOiBlcnJvcn0pKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0sXG5cbiAgICBfY3JlYXRlUHJvcGVydHlEZWZpbml0aW9uOiBmdW5jdGlvbiAobmFtZSwgZGVzYywgaXNTZXNzaW9uKSB7XG4gICAgICAgIHJldHVybiBjcmVhdGVQcm9wZXJ0eURlZmluaXRpb24odGhpcywgbmFtZSwgZGVzYywgaXNTZXNzaW9uKTtcbiAgICB9LFxuXG4gICAgLy8ganVzdCBtYWtlcyBmcmllbmRsaWVyIGVycm9ycyB3aGVuIHRyeWluZyB0byBkZWZpbmUgYSBuZXcgbW9kZWxcbiAgICAvLyBvbmx5IHVzZWQgd2hlbiBzZXR0aW5nIHVwIG9yaWdpbmFsIHByb3BlcnR5IGRlZmluaXRpb25zXG4gICAgX2Vuc3VyZVZhbGlkVHlwZTogZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgICAgcmV0dXJuIGluY2x1ZGVzKFsnc3RyaW5nJywgJ251bWJlcicsICdib29sZWFuJywgJ2FycmF5JywgJ29iamVjdCcsICdkYXRlJywgJ3N0YXRlJywgJ2FueSddXG4gICAgICAgICAgICAuY29uY2F0KE9iamVjdC5rZXlzKHRoaXMuX2RhdGFUeXBlcykpLCB0eXBlKSA/IHR5cGUgOiB1bmRlZmluZWQ7XG4gICAgfSxcblxuICAgIGdldEF0dHJpYnV0ZXM6IGZ1bmN0aW9uIChvcHRpb25zLCByYXcpIHtcbiAgICAgICAgb3B0aW9ucyA9IGFzc2lnbih7XG4gICAgICAgICAgICBzZXNzaW9uOiBmYWxzZSxcbiAgICAgICAgICAgIHByb3BzOiBmYWxzZSxcbiAgICAgICAgICAgIGRlcml2ZWQ6IGZhbHNlXG4gICAgICAgIH0sIG9wdGlvbnMgfHwge30pO1xuICAgICAgICB2YXIgcmVzID0ge307XG4gICAgICAgIHZhciB2YWwsIGRlZjtcbiAgICAgICAgZm9yICh2YXIgaXRlbSBpbiB0aGlzLl9kZWZpbml0aW9uKSB7XG4gICAgICAgICAgICBkZWYgPSB0aGlzLl9kZWZpbml0aW9uW2l0ZW1dO1xuICAgICAgICAgICAgaWYgKChvcHRpb25zLnNlc3Npb24gJiYgZGVmLnNlc3Npb24pIHx8IChvcHRpb25zLnByb3BzICYmICFkZWYuc2Vzc2lvbikpIHtcbiAgICAgICAgICAgICAgICB2YWwgPSByYXcgPyB0aGlzLl92YWx1ZXNbaXRlbV0gOiB0aGlzW2l0ZW1dO1xuICAgICAgICAgICAgICAgIGlmIChyYXcgJiYgdmFsICYmIGlzRnVuY3Rpb24odmFsLnNlcmlhbGl6ZSkpIHZhbCA9IHZhbC5zZXJpYWxpemUoKTtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbCA9PT0gJ3VuZGVmaW5lZCcpIHZhbCA9IHJlc3VsdChkZWYsICdkZWZhdWx0Jyk7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWwgIT09ICd1bmRlZmluZWQnKSByZXNbaXRlbV0gPSB2YWw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZGVyaXZlZCkge1xuICAgICAgICAgICAgZm9yICh2YXIgZGVyaXZlZEl0ZW0gaW4gdGhpcy5fZGVyaXZlZCkgcmVzW2Rlcml2ZWRJdGVtXSA9IHRoaXNbZGVyaXZlZEl0ZW1dO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfSxcblxuICAgIF9pbml0RGVyaXZlZDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgZm9yT3duKHRoaXMuX2Rlcml2ZWQsIGZ1bmN0aW9uICh2YWx1ZSwgbmFtZSkge1xuICAgICAgICAgICAgdmFyIGRlZiA9IHNlbGYuX2Rlcml2ZWRbbmFtZV07XG4gICAgICAgICAgICBkZWYuZGVwcyA9IGRlZi5kZXBMaXN0O1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBuZXdWYWwgPSBkZWYuZm4uY2FsbChzZWxmKTtcblxuICAgICAgICAgICAgICAgIGlmIChzZWxmLl9jYWNoZVtuYW1lXSAhPT0gbmV3VmFsIHx8ICFkZWYuY2FjaGUpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGRlZi5jYWNoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fcHJldmlvdXNBdHRyaWJ1dGVzW25hbWVdID0gc2VsZi5fY2FjaGVbbmFtZV07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgc2VsZi5fY2FjaGVbbmFtZV0gPSBuZXdWYWw7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYudHJpZ2dlcignY2hhbmdlOicgKyBuYW1lLCBzZWxmLCBzZWxmLl9jYWNoZVtuYW1lXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZGVmLmRlcHMuZm9yRWFjaChmdW5jdGlvbiAocHJvcFN0cmluZykge1xuICAgICAgICAgICAgICAgIHNlbGYuX2tleVRyZWUuYWRkKHByb3BTdHJpbmcsIHVwZGF0ZSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5vbignYWxsJywgZnVuY3Rpb24gKGV2ZW50TmFtZSkge1xuICAgICAgICAgICAgaWYgKGNoYW5nZVJFLnRlc3QoZXZlbnROYW1lKSkge1xuICAgICAgICAgICAgICAgIHNlbGYuX2tleVRyZWUuZ2V0KGV2ZW50TmFtZS5zcGxpdCgnOicpWzFdKS5mb3JFYWNoKGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgICAgICAgICBmbigpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LCB0aGlzKTtcbiAgICB9LFxuXG4gICAgX2dldERlcml2ZWRQcm9wZXJ0eTogZnVuY3Rpb24gKG5hbWUsIGZsdXNoQ2FjaGUpIHtcbiAgICAgICAgLy8gaXMgdGhpcyBhIGRlcml2ZWQgcHJvcGVydHkgdGhhdCBpcyBjYWNoZWRcbiAgICAgICAgaWYgKHRoaXMuX2Rlcml2ZWRbbmFtZV0uY2FjaGUpIHtcbiAgICAgICAgICAgIC8vc2V0IGlmIHRoaXMgaXMgdGhlIGZpcnN0IHRpbWUsIG9yIGZsdXNoQ2FjaGUgaXMgc2V0XG4gICAgICAgICAgICBpZiAoZmx1c2hDYWNoZSB8fCAhdGhpcy5fY2FjaGUuaGFzT3duUHJvcGVydHkobmFtZSkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9jYWNoZVtuYW1lXSA9IHRoaXMuX2Rlcml2ZWRbbmFtZV0uZm4uYXBwbHkodGhpcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fY2FjaGVbbmFtZV07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fZGVyaXZlZFtuYW1lXS5mbi5hcHBseSh0aGlzKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfaW5pdENvbGxlY3Rpb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBjb2xsO1xuICAgICAgICBpZiAoIXRoaXMuX2NvbGxlY3Rpb25zKSByZXR1cm47XG4gICAgICAgIGZvciAoY29sbCBpbiB0aGlzLl9jb2xsZWN0aW9ucykge1xuICAgICAgICAgICAgdGhpcy5fc2FmZVNldChjb2xsLCBuZXcgdGhpcy5fY29sbGVjdGlvbnNbY29sbF0obnVsbCwge3BhcmVudDogdGhpc30pKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfaW5pdENoaWxkcmVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBjaGlsZDtcbiAgICAgICAgaWYgKCF0aGlzLl9jaGlsZHJlbikgcmV0dXJuO1xuICAgICAgICBmb3IgKGNoaWxkIGluIHRoaXMuX2NoaWxkcmVuKSB7XG4gICAgICAgICAgICB0aGlzLl9zYWZlU2V0KGNoaWxkLCBuZXcgdGhpcy5fY2hpbGRyZW5bY2hpbGRdKHt9LCB7cGFyZW50OiB0aGlzfSkpO1xuICAgICAgICAgICAgdGhpcy5saXN0ZW5Ubyh0aGlzW2NoaWxkXSwgJ2FsbCcsIHRoaXMuX2dldENhY2hlZEV2ZW50QnViYmxpbmdIYW5kbGVyKGNoaWxkKSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLy8gUmV0dXJucyBhIGJvdW5kIGhhbmRsZXIgZm9yIGRvaW5nIGV2ZW50IGJ1YmJsaW5nIHdoaWxlXG4gICAgLy8gYWRkaW5nIGEgbmFtZSB0byB0aGUgY2hhbmdlIHN0cmluZy5cbiAgICBfZ2V0Q2FjaGVkRXZlbnRCdWJibGluZ0hhbmRsZXI6IGZ1bmN0aW9uIChwcm9wZXJ0eU5hbWUpIHtcbiAgICAgICAgaWYgKCF0aGlzLl9ldmVudEJ1YmJsaW5nSGFuZGxlckNhY2hlW3Byb3BlcnR5TmFtZV0pIHtcbiAgICAgICAgICAgIHRoaXMuX2V2ZW50QnViYmxpbmdIYW5kbGVyQ2FjaGVbcHJvcGVydHlOYW1lXSA9IGZ1bmN0aW9uIChuYW1lLCBtb2RlbCwgbmV3VmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAoY2hhbmdlUkUudGVzdChuYW1lKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnRyaWdnZXIoJ2NoYW5nZTonICsgcHJvcGVydHlOYW1lICsgJy4nICsgbmFtZS5zcGxpdCgnOicpWzFdLCBtb2RlbCwgbmV3VmFsdWUpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobmFtZSA9PT0gJ2NoYW5nZScpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy50cmlnZ2VyKCdjaGFuZ2UnLCB0aGlzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LmJpbmQodGhpcyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuX2V2ZW50QnViYmxpbmdIYW5kbGVyQ2FjaGVbcHJvcGVydHlOYW1lXTtcbiAgICB9LFxuXG4gICAgLy8gQ2hlY2sgdGhhdCBhbGwgcmVxdWlyZWQgYXR0cmlidXRlcyBhcmUgcHJlc2VudFxuICAgIF92ZXJpZnlSZXF1aXJlZDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgYXR0cnMgPSB0aGlzLmF0dHJpYnV0ZXM7IC8vIHNob3VsZCBpbmNsdWRlIHNlc3Npb25cbiAgICAgICAgZm9yICh2YXIgZGVmIGluIHRoaXMuX2RlZmluaXRpb24pIHtcbiAgICAgICAgICAgIGlmICh0aGlzLl9kZWZpbml0aW9uW2RlZl0ucmVxdWlyZWQgJiYgdHlwZW9mIGF0dHJzW2RlZl0gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0sXG5cbiAgICAvLyBleHBvc2Ugc2FmZVNldCBtZXRob2RcbiAgICBfc2FmZVNldDogZnVuY3Rpb24gc2FmZVNldChwcm9wZXJ0eSwgdmFsdWUpIHtcbiAgICAgICAgaWYgKHByb3BlcnR5IGluIHRoaXMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignRW5jb3VudGVyZWQgbmFtZXNwYWNlIGNvbGxpc2lvbiB3aGlsZSBzZXR0aW5nIGluc3RhbmNlIHByb3BlcnR5IGAnICsgcHJvcGVydHkgKyAnYCcpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXNbcHJvcGVydHldID0gdmFsdWU7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbn0pO1xuXG4vLyBnZXR0ZXIgZm9yIGF0dHJpYnV0ZXNcbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEJhc2UucHJvdG90eXBlLCB7XG4gICAgYXR0cmlidXRlczoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldEF0dHJpYnV0ZXMoe3Byb3BzOiB0cnVlLCBzZXNzaW9uOiB0cnVlfSk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGFsbDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldEF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgICAgIHNlc3Npb246IHRydWUsXG4gICAgICAgICAgICAgICAgcHJvcHM6IHRydWUsXG4gICAgICAgICAgICAgICAgZGVyaXZlZDogdHJ1ZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGlzU3RhdGU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7IHJldHVybiB0cnVlOyB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICgpIHsgfVxuICAgIH1cbn0pO1xuXG4vLyBoZWxwZXIgZm9yIGNyZWF0aW5nL3N0b3JpbmcgcHJvcGVydHkgZGVmaW5pdGlvbnMgYW5kIGNyZWF0aW5nXG4vLyBhcHByb3ByaWF0ZSBnZXR0ZXJzL3NldHRlcnNcbmZ1bmN0aW9uIGNyZWF0ZVByb3BlcnR5RGVmaW5pdGlvbihvYmplY3QsIG5hbWUsIGRlc2MsIGlzU2Vzc2lvbikge1xuICAgIHZhciBkZWYgPSBvYmplY3QuX2RlZmluaXRpb25bbmFtZV0gPSB7fTtcbiAgICB2YXIgdHlwZSwgZGVzY0FycmF5O1xuXG4gICAgaWYgKGlzU3RyaW5nKGRlc2MpKSB7XG4gICAgICAgIC8vIGdyYWIgb3VyIHR5cGUgaWYgYWxsIHdlJ3ZlIGdvdCBpcyBhIHN0cmluZ1xuICAgICAgICB0eXBlID0gb2JqZWN0Ll9lbnN1cmVWYWxpZFR5cGUoZGVzYyk7XG4gICAgICAgIGlmICh0eXBlKSBkZWYudHlwZSA9IHR5cGU7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy9UcmFuc2Zvcm0gYXJyYXkgb2YgWyd0eXBlJywgcmVxdWlyZWQsIGRlZmF1bHRdIHRvIG9iamVjdCBmb3JtXG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KGRlc2MpKSB7XG4gICAgICAgICAgICBkZXNjQXJyYXkgPSBkZXNjO1xuICAgICAgICAgICAgZGVzYyA9IHtcbiAgICAgICAgICAgICAgICB0eXBlOiBkZXNjQXJyYXlbMF0sXG4gICAgICAgICAgICAgICAgcmVxdWlyZWQ6IGRlc2NBcnJheVsxXSxcbiAgICAgICAgICAgICAgICAnZGVmYXVsdCc6IGRlc2NBcnJheVsyXVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHR5cGUgPSBvYmplY3QuX2Vuc3VyZVZhbGlkVHlwZShkZXNjLnR5cGUpO1xuICAgICAgICBpZiAodHlwZSkgZGVmLnR5cGUgPSB0eXBlO1xuXG4gICAgICAgIGlmIChkZXNjLnJlcXVpcmVkKSBkZWYucmVxdWlyZWQgPSB0cnVlO1xuXG4gICAgICAgIGlmIChkZXNjWydkZWZhdWx0J10gJiYgdHlwZW9mIGRlc2NbJ2RlZmF1bHQnXSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1RoZSBkZWZhdWx0IHZhbHVlIGZvciAnICsgbmFtZSArICcgY2Fubm90IGJlIGFuIG9iamVjdC9hcnJheSwgbXVzdCBiZSBhIHZhbHVlIG9yIGEgZnVuY3Rpb24gd2hpY2ggcmV0dXJucyBhIHZhbHVlL29iamVjdC9hcnJheScpO1xuICAgICAgICB9XG5cbiAgICAgICAgZGVmWydkZWZhdWx0J10gPSBkZXNjWydkZWZhdWx0J107XG5cbiAgICAgICAgZGVmLmFsbG93TnVsbCA9IGRlc2MuYWxsb3dOdWxsID8gZGVzYy5hbGxvd051bGwgOiBmYWxzZTtcbiAgICAgICAgaWYgKGRlc2Muc2V0T25jZSkgZGVmLnNldE9uY2UgPSB0cnVlO1xuICAgICAgICBpZiAoZGVmLnJlcXVpcmVkICYmIGRlZlsnZGVmYXVsdCddID09PSB1bmRlZmluZWQgJiYgIWRlZi5zZXRPbmNlKSBkZWZbJ2RlZmF1bHQnXSA9IG9iamVjdC5fZ2V0RGVmYXVsdEZvclR5cGUodHlwZSk7XG4gICAgICAgIGRlZi50ZXN0ID0gZGVzYy50ZXN0O1xuICAgICAgICBkZWYudmFsdWVzID0gZGVzYy52YWx1ZXM7XG4gICAgfVxuICAgIGlmIChpc1Nlc3Npb24pIGRlZi5zZXNzaW9uID0gdHJ1ZTtcblxuICAgIGlmICghdHlwZSkge1xuICAgICAgICB0eXBlID0gaXNTdHJpbmcoZGVzYykgPyBkZXNjIDogZGVzYy50eXBlO1xuICAgICAgICAvLyBUT0RPOiBzdGFydCB0aHJvd2luZyBhIFR5cGVFcnJvciBpbiBmdXR1cmUgbWFqb3IgdmVyc2lvbnMgaW5zdGVhZCBvZiB3YXJuaW5nXG4gICAgICAgIGNvbnNvbGUud2FybignSW52YWxpZCBkYXRhIHR5cGUgb2YgYCcgKyB0eXBlICsgJ2AgZm9yIGAnICsgbmFtZSArICdgIHByb3BlcnR5LiBVc2Ugb25lIG9mIHRoZSBkZWZhdWx0IHR5cGVzIG9yIGRlZmluZSB5b3VyIG93bicpO1xuICAgIH1cblxuICAgIC8vIGRlZmluZSBhIGdldHRlci9zZXR0ZXIgb24gdGhlIHByb3RvdHlwZVxuICAgIC8vIGJ1dCB0aGV5IGdldC9zZXQgb24gdGhlIGluc3RhbmNlXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iamVjdCwgbmFtZSwge1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWwpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0KG5hbWUsIHZhbCk7XG4gICAgICAgIH0sXG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKCF0aGlzLl92YWx1ZXMpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBFcnJvcignWW91IG1heSBiZSB0cnlpbmcgdG8gYGV4dGVuZGAgYSBzdGF0ZSBvYmplY3Qgd2l0aCBcIicgKyBuYW1lICsgJ1wiIHdoaWNoIGhhcyBiZWVuIGRlZmluZWQgaW4gYHByb3BzYCBvbiB0aGUgb2JqZWN0IGJlaW5nIGV4dGVuZGVkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgdmFsdWUgPSB0aGlzLl92YWx1ZXNbbmFtZV07XG4gICAgICAgICAgICB2YXIgdHlwZURlZiA9IHRoaXMuX2RhdGFUeXBlc1tkZWYudHlwZV07XG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlRGVmICYmIHR5cGVEZWYuZ2V0KSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdHlwZURlZi5nZXQodmFsdWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgZGVmYXVsdFZhbHVlID0gcmVzdWx0KGRlZiwgJ2RlZmF1bHQnKTtcbiAgICAgICAgICAgIHRoaXMuX3ZhbHVlc1tuYW1lXSA9IGRlZmF1bHRWYWx1ZTtcbiAgICAgICAgICAgIC8vIElmIHdlJ3ZlIHNldCBhIGRlZmF1bHRWYWx1ZSwgZmlyZSBhIGNoYW5nZSBoYW5kbGVyIGVmZmVjdGl2ZWx5IG1hcmtpbmdcbiAgICAgICAgICAgIC8vIGl0cyBjaGFuZ2UgZnJvbSB1bmRlZmluZWQgdG8gdGhlIGRlZmF1bHQgdmFsdWUuXG4gICAgICAgICAgICBpZiAodHlwZW9mIGRlZmF1bHRWYWx1ZSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICB2YXIgb25DaGFuZ2UgPSB0aGlzLl9nZXRPbkNoYW5nZUZvclR5cGUoZGVmLnR5cGUpO1xuICAgICAgICAgICAgICAgIG9uQ2hhbmdlKGRlZmF1bHRWYWx1ZSwgdmFsdWUsIG5hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGRlZmF1bHRWYWx1ZTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGRlZjtcbn1cblxuLy8gaGVscGVyIGZvciBjcmVhdGluZyBkZXJpdmVkIHByb3BlcnR5IGRlZmluaXRpb25zXG5mdW5jdGlvbiBjcmVhdGVEZXJpdmVkUHJvcGVydHkobW9kZWxQcm90bywgbmFtZSwgZGVmaW5pdGlvbikge1xuICAgIHZhciBkZWYgPSBtb2RlbFByb3RvLl9kZXJpdmVkW25hbWVdID0ge1xuICAgICAgICBmbjogaXNGdW5jdGlvbihkZWZpbml0aW9uKSA/IGRlZmluaXRpb24gOiBkZWZpbml0aW9uLmZuLFxuICAgICAgICBjYWNoZTogKGRlZmluaXRpb24uY2FjaGUgIT09IGZhbHNlKSxcbiAgICAgICAgZGVwTGlzdDogZGVmaW5pdGlvbi5kZXBzIHx8IFtdXG4gICAgfTtcblxuICAgIC8vIGFkZCB0byBvdXIgc2hhcmVkIGRlcGVuZGVuY3kgbGlzdFxuICAgIGRlZi5kZXBMaXN0LmZvckVhY2goZnVuY3Rpb24gKGRlcCkge1xuICAgICAgICBtb2RlbFByb3RvLl9kZXBzW2RlcF0gPSB1bmlvbihtb2RlbFByb3RvLl9kZXBzW2RlcF0gfHwgW10sIFtuYW1lXSk7XG4gICAgfSk7XG5cbiAgICAvLyBkZWZpbmVkIGEgdG9wLWxldmVsIGdldHRlciBmb3IgZGVyaXZlZCBuYW1lc1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShtb2RlbFByb3RvLCBuYW1lLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2dldERlcml2ZWRQcm9wZXJ0eShuYW1lKTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYFwiICsgbmFtZSArIFwiYCBpcyBhIGRlcml2ZWQgcHJvcGVydHksIGl0IGNhbid0IGJlIHNldCBkaXJlY3RseS5cIik7XG4gICAgICAgIH1cbiAgICB9KTtcbn1cblxudmFyIGRhdGFUeXBlcyA9IHtcbiAgICBzdHJpbmc6IHtcbiAgICAgICAgJ2RlZmF1bHQnOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGRhdGU6IHtcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAobmV3VmFsKSB7XG4gICAgICAgICAgICB2YXIgbmV3VHlwZTtcbiAgICAgICAgICAgIGlmIChuZXdWYWwgPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIG5ld1R5cGUgPSB0eXBlb2YgbnVsbDtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIWlzRGF0ZShuZXdWYWwpKSB7XG4gICAgICAgICAgICAgICAgdmFyIGVyciA9IG51bGw7XG4gICAgICAgICAgICAgICAgdmFyIGRhdGVWYWwgPSBuZXcgRGF0ZShuZXdWYWwpLnZhbHVlT2YoKTtcbiAgICAgICAgICAgICAgICBpZiAoaXNOYU4oZGF0ZVZhbCkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhlIG5ld1ZhbCBjYW50IGJlIHBhcnNlZCwgdGhlbiB0cnkgcGFyc2VJbnQgZmlyc3RcbiAgICAgICAgICAgICAgICAgICAgZGF0ZVZhbCA9IG5ldyBEYXRlKHBhcnNlSW50KG5ld1ZhbCwgMTApKS52YWx1ZU9mKCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpc05hTihkYXRlVmFsKSkgZXJyID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbmV3VmFsID0gZGF0ZVZhbDtcbiAgICAgICAgICAgICAgICBuZXdUeXBlID0gJ2RhdGUnO1xuICAgICAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgbmV3VHlwZSA9IHR5cGVvZiBuZXdWYWw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBuZXdUeXBlID0gJ2RhdGUnO1xuICAgICAgICAgICAgICAgIG5ld1ZhbCA9IG5ld1ZhbC52YWx1ZU9mKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgdmFsOiBuZXdWYWwsXG4gICAgICAgICAgICAgICAgdHlwZTogbmV3VHlwZVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAodmFsKSB7XG4gICAgICAgICAgICBpZiAodmFsID09IG51bGwpIHsgcmV0dXJuIHZhbDsgfVxuICAgICAgICAgICAgcmV0dXJuIG5ldyBEYXRlKHZhbCk7XG4gICAgICAgIH0sXG4gICAgICAgICdkZWZhdWx0JzogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBEYXRlKCk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGFycmF5OiB7XG4gICAgICAgIHNldDogZnVuY3Rpb24gKG5ld1ZhbCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB2YWw6IG5ld1ZhbCxcbiAgICAgICAgICAgICAgICB0eXBlOiBBcnJheS5pc0FycmF5KG5ld1ZhbCkgPyAnYXJyYXknIDogdHlwZW9mIG5ld1ZhbFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgJ2RlZmF1bHQnOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgIH1cbiAgICB9LFxuICAgIG9iamVjdDoge1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChuZXdWYWwpIHtcbiAgICAgICAgICAgIHZhciBuZXdUeXBlID0gdHlwZW9mIG5ld1ZhbDtcbiAgICAgICAgICAgIC8vIHdlIGhhdmUgdG8gaGF2ZSBhIHdheSBvZiBzdXBwb3J0aW5nIFwibWlzc2luZ1wiIG9iamVjdHMuXG4gICAgICAgICAgICAvLyBOdWxsIGlzIGFuIG9iamVjdCwgYnV0IHNldHRpbmcgYSB2YWx1ZSB0byB1bmRlZmluZWRcbiAgICAgICAgICAgIC8vIHNob3VsZCB3b3JrIHRvbywgSU1PLiBXZSBqdXN0IG92ZXJyaWRlIGl0LCBpbiB0aGF0IGNhc2UuXG4gICAgICAgICAgICBpZiAobmV3VHlwZSAhPT0gJ29iamVjdCcgJiYgbmV3VmFsID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBuZXdWYWwgPSBudWxsO1xuICAgICAgICAgICAgICAgIG5ld1R5cGUgPSAnb2JqZWN0JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgdmFsOiBuZXdWYWwsXG4gICAgICAgICAgICAgICAgdHlwZTogbmV3VHlwZVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgJ2RlZmF1bHQnOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4ge307XG4gICAgICAgIH1cbiAgICB9LFxuICAgIC8vIHRoZSBgc3RhdGVgIGRhdGEgdHlwZSBpcyBhIGJpdCBzcGVjaWFsIGluIHRoYXQgc2V0dGluZyBpdCBzaG91bGRcbiAgICAvLyBhbHNvIGJ1YmJsZSBldmVudHNcbiAgICBzdGF0ZToge1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChuZXdWYWwpIHtcbiAgICAgICAgICAgIHZhciBpc0luc3RhbmNlID0gbmV3VmFsIGluc3RhbmNlb2YgQmFzZSB8fCAobmV3VmFsICYmIG5ld1ZhbC5pc1N0YXRlKTtcbiAgICAgICAgICAgIGlmIChpc0luc3RhbmNlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsOiBuZXdWYWwsXG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdzdGF0ZSdcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICB2YWw6IG5ld1ZhbCxcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogdHlwZW9mIG5ld1ZhbFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGNvbXBhcmU6IGZ1bmN0aW9uIChjdXJyZW50VmFsLCBuZXdWYWwpIHtcbiAgICAgICAgICAgIHJldHVybiBjdXJyZW50VmFsID09PSBuZXdWYWw7XG4gICAgICAgIH0sXG5cbiAgICAgICAgb25DaGFuZ2UgOiBmdW5jdGlvbihuZXdWYWwsIHByZXZpb3VzVmFsLCBhdHRyaWJ1dGVOYW1lKXtcbiAgICAgICAgICAgIC8vIGlmIHRoaXMgaGFzIGNoYW5nZWQgd2Ugd2FudCB0byBhbHNvIGhhbmRsZVxuICAgICAgICAgICAgLy8gZXZlbnQgcHJvcGFnYXRpb25cbiAgICAgICAgICAgIGlmIChwcmV2aW91c1ZhbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuc3RvcExpc3RlbmluZyhwcmV2aW91c1ZhbCwgJ2FsbCcsIHRoaXMuX2dldENhY2hlZEV2ZW50QnViYmxpbmdIYW5kbGVyKGF0dHJpYnV0ZU5hbWUpKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKG5ld1ZhbCAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5saXN0ZW5UbyhuZXdWYWwsICdhbGwnLCB0aGlzLl9nZXRDYWNoZWRFdmVudEJ1YmJsaW5nSGFuZGxlcihhdHRyaWJ1dGVOYW1lKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vLyB0aGUgZXh0ZW5kIG1ldGhvZCB1c2VkIHRvIGV4dGVuZCBwcm90b3R5cGVzLCBtYWludGFpbiBpbmhlcml0YW5jZSBjaGFpbnMgZm9yIGluc3RhbmNlb2Zcbi8vIGFuZCBhbGxvdyBmb3IgYWRkaXRpb25zIHRvIHRoZSBtb2RlbCBkZWZpbml0aW9ucy5cbmZ1bmN0aW9uIGV4dGVuZChwcm90b1Byb3BzKSB7XG4gICAgLypqc2hpbnQgdmFsaWR0aGlzOnRydWUqL1xuICAgIHZhciBwYXJlbnQgPSB0aGlzO1xuICAgIHZhciBjaGlsZDtcblxuICAgIC8vIFRoZSBjb25zdHJ1Y3RvciBmdW5jdGlvbiBmb3IgdGhlIG5ldyBzdWJjbGFzcyBpcyBlaXRoZXIgZGVmaW5lZCBieSB5b3VcbiAgICAvLyAodGhlIFwiY29uc3RydWN0b3JcIiBwcm9wZXJ0eSBpbiB5b3VyIGBleHRlbmRgIGRlZmluaXRpb24pLCBvciBkZWZhdWx0ZWRcbiAgICAvLyBieSB1cyB0byBzaW1wbHkgY2FsbCB0aGUgcGFyZW50J3MgY29uc3RydWN0b3IuXG4gICAgaWYgKHByb3RvUHJvcHMgJiYgcHJvdG9Qcm9wcy5oYXNPd25Qcm9wZXJ0eSgnY29uc3RydWN0b3InKSkge1xuICAgICAgICBjaGlsZCA9IHByb3RvUHJvcHMuY29uc3RydWN0b3I7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgY2hpbGQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gcGFyZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gQWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjb25zdHJ1Y3RvciBmdW5jdGlvbiBmcm9tIHBhcmVudFxuICAgIGFzc2lnbihjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIFNldCB0aGUgcHJvdG90eXBlIGNoYWluIHRvIGluaGVyaXQgZnJvbSBgcGFyZW50YCwgd2l0aG91dCBjYWxsaW5nXG4gICAgLy8gYHBhcmVudGAncyBjb25zdHJ1Y3RvciBmdW5jdGlvbi5cbiAgICB2YXIgU3Vycm9nYXRlID0gZnVuY3Rpb24gKCkgeyB0aGlzLmNvbnN0cnVjdG9yID0gY2hpbGQ7IH07XG4gICAgU3Vycm9nYXRlLnByb3RvdHlwZSA9IHBhcmVudC5wcm90b3R5cGU7XG4gICAgY2hpbGQucHJvdG90eXBlID0gbmV3IFN1cnJvZ2F0ZSgpO1xuXG4gICAgLy8gc2V0IHByb3RvdHlwZSBsZXZlbCBvYmplY3RzXG4gICAgY2hpbGQucHJvdG90eXBlLl9kZXJpdmVkID0gIGFzc2lnbih7fSwgcGFyZW50LnByb3RvdHlwZS5fZGVyaXZlZCk7XG4gICAgY2hpbGQucHJvdG90eXBlLl9kZXBzID0gYXNzaWduKHt9LCBwYXJlbnQucHJvdG90eXBlLl9kZXBzKTtcbiAgICBjaGlsZC5wcm90b3R5cGUuX2RlZmluaXRpb24gPSBhc3NpZ24oe30sIHBhcmVudC5wcm90b3R5cGUuX2RlZmluaXRpb24pO1xuICAgIGNoaWxkLnByb3RvdHlwZS5fY29sbGVjdGlvbnMgPSBhc3NpZ24oe30sIHBhcmVudC5wcm90b3R5cGUuX2NvbGxlY3Rpb25zKTtcbiAgICBjaGlsZC5wcm90b3R5cGUuX2NoaWxkcmVuID0gYXNzaWduKHt9LCBwYXJlbnQucHJvdG90eXBlLl9jaGlsZHJlbik7XG4gICAgY2hpbGQucHJvdG90eXBlLl9kYXRhVHlwZXMgPSBhc3NpZ24oe30sIHBhcmVudC5wcm90b3R5cGUuX2RhdGFUeXBlcyB8fCBkYXRhVHlwZXMpO1xuXG4gICAgLy8gTWl4IGluIGFsbCBwcm90b3R5cGUgcHJvcGVydGllcyB0byB0aGUgc3ViY2xhc3MgaWYgc3VwcGxpZWQuXG4gICAgaWYgKHByb3RvUHJvcHMpIHtcbiAgICAgICAgdmFyIG9taXRGcm9tRXh0ZW5kID0gW1xuICAgICAgICAgICAgJ2RhdGFUeXBlcycsICdwcm9wcycsICdzZXNzaW9uJywgJ2Rlcml2ZWQnLCAnY29sbGVjdGlvbnMnLCAnY2hpbGRyZW4nXG4gICAgICAgIF07XG4gICAgICAgIGZvcih2YXIgaSA9IDA7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHZhciBkZWYgPSBhcmd1bWVudHNbaV07XG4gICAgICAgICAgICBpZiAoZGVmLmRhdGFUeXBlcykge1xuICAgICAgICAgICAgICAgIGZvck93bihkZWYuZGF0YVR5cGVzLCBmdW5jdGlvbiAoZGVmLCBuYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIGNoaWxkLnByb3RvdHlwZS5fZGF0YVR5cGVzW25hbWVdID0gZGVmO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRlZi5wcm9wcykge1xuICAgICAgICAgICAgICAgIGZvck93bihkZWYucHJvcHMsIGZ1bmN0aW9uIChkZWYsIG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgY3JlYXRlUHJvcGVydHlEZWZpbml0aW9uKGNoaWxkLnByb3RvdHlwZSwgbmFtZSwgZGVmKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChkZWYuc2Vzc2lvbikge1xuICAgICAgICAgICAgICAgIGZvck93bihkZWYuc2Vzc2lvbiwgZnVuY3Rpb24gKGRlZiwgbmFtZSkge1xuICAgICAgICAgICAgICAgICAgICBjcmVhdGVQcm9wZXJ0eURlZmluaXRpb24oY2hpbGQucHJvdG90eXBlLCBuYW1lLCBkZWYsIHRydWUpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRlZi5kZXJpdmVkKSB7XG4gICAgICAgICAgICAgICAgZm9yT3duKGRlZi5kZXJpdmVkLCBmdW5jdGlvbiAoZGVmLCBuYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZURlcml2ZWRQcm9wZXJ0eShjaGlsZC5wcm90b3R5cGUsIG5hbWUsIGRlZik7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZGVmLmNvbGxlY3Rpb25zKSB7XG4gICAgICAgICAgICAgICAgZm9yT3duKGRlZi5jb2xsZWN0aW9ucywgZnVuY3Rpb24gKGNvbnN0cnVjdG9yLCBuYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIGNoaWxkLnByb3RvdHlwZS5fY29sbGVjdGlvbnNbbmFtZV0gPSBjb25zdHJ1Y3RvcjtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChkZWYuY2hpbGRyZW4pIHtcbiAgICAgICAgICAgICAgICBmb3JPd24oZGVmLmNoaWxkcmVuLCBmdW5jdGlvbiAoY29uc3RydWN0b3IsIG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgY2hpbGQucHJvdG90eXBlLl9jaGlsZHJlbltuYW1lXSA9IGNvbnN0cnVjdG9yO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXNzaWduKGNoaWxkLnByb3RvdHlwZSwgb21pdChkZWYsIG9taXRGcm9tRXh0ZW5kKSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBTZXQgYSBjb252ZW5pZW5jZSBwcm9wZXJ0eSBpbiBjYXNlIHRoZSBwYXJlbnQncyBwcm90b3R5cGUgaXMgbmVlZGVkXG4gICAgLy8gbGF0ZXIuXG4gICAgY2hpbGQuX19zdXBlcl9fID0gcGFyZW50LnByb3RvdHlwZTtcblxuICAgIHJldHVybiBjaGlsZDtcbn1cblxuQmFzZS5leHRlbmQgPSBleHRlbmQ7XG5cbi8vIE91ciBtYWluIGV4cG9ydHNcbm1vZHVsZS5leHBvcnRzID0gQmFzZTtcbiJdLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTsiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///ef45\n")}}]);

There are no issues that match your filters.

Category
Status