(function (f) { if (typeof exports === "object" && typeof module !== "undefined") { module.exports = f() } else if (typeof define === "function" && define.amd) { define([], f) } else { var g; if (typeof window !== "undefined") { g = window } else if (typeof global !== "undefined") { g = global } else if (typeof self !== "undefined") { g = self } else { g = this } g.netlistsvg = f() } })(function () {
    var define, module, exports; return (function () { function r(e, n, t) { function o(i, f) { if (!n[i]) { if (!e[i]) { var c = "function" == typeof require && require; if (!f && c) return c(i, !0); if (u) return u(i, !0); var a = new Error("Cannot find module '" + i + "'"); throw a.code = "MODULE_NOT_FOUND", a } var p = n[i] = { exports: {} }; e[i][0].call(p.exports, function (r) { var n = e[i][1][r]; return o(n || r) }, p, p.exports, r, e, n, t) } return n[i].exports } for (var u = "function" == typeof require && require, i = 0; i < t.length; i++)o(t[i]); return o } return r })()({
        1: [function (require, module, exports) {
            'use strict'

            exports.byteLength = byteLength
            exports.toByteArray = toByteArray
            exports.fromByteArray = fromByteArray

            var lookup = []
            var revLookup = []
            var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array

            var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
            for (var i = 0, len = code.length; i < len; ++i) {
                lookup[i] = code[i]
                revLookup[code.charCodeAt(i)] = i
            }

            // Support decoding URL-safe base64 strings, as Node.js does.
            // See: https://en.wikipedia.org/wiki/Base64#URL_applications
            revLookup['-'.charCodeAt(0)] = 62
            revLookup['_'.charCodeAt(0)] = 63

            function getLens(b64) {
                var len = b64.length

                if (len % 4 > 0) {
                    throw new Error('Invalid string. Length must be a multiple of 4')
                }

                // Trim off extra bytes after placeholder bytes are found
                // See: https://github.com/beatgammit/base64-js/issues/42
                var validLen = b64.indexOf('=')
                if (validLen === -1) validLen = len

                var placeHoldersLen = validLen === len
                    ? 0
                    : 4 - (validLen % 4)

                return [validLen, placeHoldersLen]
            }

            // base64 is 4/3 + up to two characters of the original data
            function byteLength(b64) {
                var lens = getLens(b64)
                var validLen = lens[0]
                var placeHoldersLen = lens[1]
                return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
            }

            function _byteLength(b64, validLen, placeHoldersLen) {
                return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
            }

            function toByteArray(b64) {
                var tmp
                var lens = getLens(b64)
                var validLen = lens[0]
                var placeHoldersLen = lens[1]

                var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))

                var curByte = 0

                // if there are placeholders, only get up to the last complete 4 chars
                var len = placeHoldersLen > 0
                    ? validLen - 4
                    : validLen

                var i
                for (i = 0; i < len; i += 4) {
                    tmp =
                        (revLookup[b64.charCodeAt(i)] << 18) |
                        (revLookup[b64.charCodeAt(i + 1)] << 12) |
                        (revLookup[b64.charCodeAt(i + 2)] << 6) |
                        revLookup[b64.charCodeAt(i + 3)]
                    arr[curByte++] = (tmp >> 16) & 0xFF
                    arr[curByte++] = (tmp >> 8) & 0xFF
                    arr[curByte++] = tmp & 0xFF
                }

                if (placeHoldersLen === 2) {
                    tmp =
                        (revLookup[b64.charCodeAt(i)] << 2) |
                        (revLookup[b64.charCodeAt(i + 1)] >> 4)
                    arr[curByte++] = tmp & 0xFF
                }

                if (placeHoldersLen === 1) {
                    tmp =
                        (revLookup[b64.charCodeAt(i)] << 10) |
                        (revLookup[b64.charCodeAt(i + 1)] << 4) |
                        (revLookup[b64.charCodeAt(i + 2)] >> 2)
                    arr[curByte++] = (tmp >> 8) & 0xFF
                    arr[curByte++] = tmp & 0xFF
                }

                return arr
            }

            function tripletToBase64(num) {
                return lookup[num >> 18 & 0x3F] +
                    lookup[num >> 12 & 0x3F] +
                    lookup[num >> 6 & 0x3F] +
                    lookup[num & 0x3F]
            }

            function encodeChunk(uint8, start, end) {
                var tmp
                var output = []
                for (var i = start; i < end; i += 3) {
                    tmp =
                        ((uint8[i] << 16) & 0xFF0000) +
                        ((uint8[i + 1] << 8) & 0xFF00) +
                        (uint8[i + 2] & 0xFF)
                    output.push(tripletToBase64(tmp))
                }
                return output.join('')
            }

            function fromByteArray(uint8) {
                var tmp
                var len = uint8.length
                var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
                var parts = []
                var maxChunkLength = 16383 // must be multiple of 3

                // go through the array every three bytes, we'll deal with trailing stuff later
                for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
                    parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))
                }

                // pad the end with zeros, but make sure to not forget the extra bytes
                if (extraBytes === 1) {
                    tmp = uint8[len - 1]
                    parts.push(
                        lookup[tmp >> 2] +
                        lookup[(tmp << 4) & 0x3F] +
                        '=='
                    )
                } else if (extraBytes === 2) {
                    tmp = (uint8[len - 2] << 8) + uint8[len - 1]
                    parts.push(
                        lookup[tmp >> 10] +
                        lookup[(tmp >> 4) & 0x3F] +
                        lookup[(tmp << 2) & 0x3F] +
                        '='
                    )
                }

                return parts.join('')
            }

        }, {}], 2: [function (require, module, exports) {

        }, {}], 3: [function (require, module, exports) {
            (function (Buffer) {
                (function () {
                    /*!
                     * The buffer module from node.js, for the browser.
                     *
                     * @author   Feross Aboukhadijeh <https://feross.org>
                     * @license  MIT
                     */
                    /* eslint-disable no-proto */

                    'use strict'

                    var base64 = require('base64-js');
                    var ieee754 = require('ieee754');

                    exports.Buffer = Buffer
                    exports.SlowBuffer = SlowBuffer
                    exports.INSPECT_MAX_BYTES = 50

                    var K_MAX_LENGTH = 0x7fffffff
                    exports.kMaxLength = K_MAX_LENGTH

                    /**
                     * If `Buffer.TYPED_ARRAY_SUPPORT`:
                     *   === true    Use Uint8Array implementation (fastest)
                     *   === false   Print warning and recommend using `buffer` v4.x which has an Object
                     *               implementation (most compatible, even IE6)
                     *
                     * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
                     * Opera 11.6+, iOS 4.2+.
                     *
                     * We report that the browser does not support typed arrays if the are not subclassable
                     * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array`
                     * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support
                     * for __proto__ and has a buggy typed array implementation.
                     */
                    Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport()

                    if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' &&
                        typeof console.error === 'function') {
                        console.error(
                            'This browser lacks typed array (Uint8Array) support which is required by ' +
                            '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.'
                        )
                    }

                    function typedArraySupport() {
                        // Can typed array instances can be augmented?
                        try {
                            var arr = new Uint8Array(1)
                            arr.__proto__ = { __proto__: Uint8Array.prototype, foo: function () { return 42 } }
                            return arr.foo() === 42
                        } catch (e) {
                            return false
                        }
                    }

                    Object.defineProperty(Buffer.prototype, 'parent', {
                        enumerable: true,
                        get: function () {
                            if (!Buffer.isBuffer(this)) return undefined
                            return this.buffer
                        }
                    })

                    Object.defineProperty(Buffer.prototype, 'offset', {
                        enumerable: true,
                        get: function () {
                            if (!Buffer.isBuffer(this)) return undefined
                            return this.byteOffset
                        }
                    })

                    function createBuffer(length) {
                        if (length > K_MAX_LENGTH) {
                            throw new RangeError('The value "' + length + '" is invalid for option "size"')
                        }
                        // Return an augmented `Uint8Array` instance
                        var buf = new Uint8Array(length)
                        buf.__proto__ = Buffer.prototype
                        return buf
                    }

                    /**
                     * The Buffer constructor returns instances of `Uint8Array` that have their
                     * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
                     * `Uint8Array`, so the returned instances will have all the node `Buffer` methods
                     * and the `Uint8Array` methods. Square bracket notation works as expected -- it
                     * returns a single octet.
                     *
                     * The `Uint8Array` prototype remains unmodified.
                     */

                    function Buffer(arg, encodingOrOffset, length) {
                        // Common case.
                        if (typeof arg === 'number') {
                            if (typeof encodingOrOffset === 'string') {
                                throw new TypeError(
                                    'The "string" argument must be of type string. Received type number'
                                )
                            }
                            return allocUnsafe(arg)
                        }
                        return from(arg, encodingOrOffset, length)
                    }

                    // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
                    if (typeof Symbol !== 'undefined' && Symbol.species != null &&
                        Buffer[Symbol.species] === Buffer) {
                        Object.defineProperty(Buffer, Symbol.species, {
                            value: null,
                            configurable: true,
                            enumerable: false,
                            writable: false
                        })
                    }

                    Buffer.poolSize = 8192 // not used by this implementation

                    function from(value, encodingOrOffset, length) {
                        if (typeof value === 'string') {
                            return fromString(value, encodingOrOffset)
                        }

                        if (ArrayBuffer.isView(value)) {
                            return fromArrayLike(value)
                        }

                        if (value == null) {
                            throw TypeError(
                                'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' +
                                'or Array-like Object. Received type ' + (typeof value)
                            )
                        }

                        if (isInstance(value, ArrayBuffer) ||
                            (value && isInstance(value.buffer, ArrayBuffer))) {
                            return fromArrayBuffer(value, encodingOrOffset, length)
                        }

                        if (typeof value === 'number') {
                            throw new TypeError(
                                'The "value" argument must not be of type number. Received type number'
                            )
                        }

                        var valueOf = value.valueOf && value.valueOf()
                        if (valueOf != null && valueOf !== value) {
                            return Buffer.from(valueOf, encodingOrOffset, length)
                        }

                        var b = fromObject(value)
                        if (b) return b

                        if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null &&
                            typeof value[Symbol.toPrimitive] === 'function') {
                            return Buffer.from(
                                value[Symbol.toPrimitive]('string'), encodingOrOffset, length
                            )
                        }

                        throw new TypeError(
                            'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' +
                            'or Array-like Object. Received type ' + (typeof value)
                        )
                    }

                    /**
                     * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
                     * if value is a number.
                     * Buffer.from(str[, encoding])
                     * Buffer.from(array)
                     * Buffer.from(buffer)
                     * Buffer.from(arrayBuffer[, byteOffset[, length]])
                     **/
                    Buffer.from = function (value, encodingOrOffset, length) {
                        return from(value, encodingOrOffset, length)
                    }

                    // Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug:
                    // https://github.com/feross/buffer/pull/148
                    Buffer.prototype.__proto__ = Uint8Array.prototype
                    Buffer.__proto__ = Uint8Array

                    function assertSize(size) {
                        if (typeof size !== 'number') {
                            throw new TypeError('"size" argument must be of type number')
                        } else if (size < 0) {
                            throw new RangeError('The value "' + size + '" is invalid for option "size"')
                        }
                    }

                    function alloc(size, fill, encoding) {
                        assertSize(size)
                        if (size <= 0) {
                            return createBuffer(size)
                        }
                        if (fill !== undefined) {
                            // Only pay attention to encoding if it's a string. This
                            // prevents accidentally sending in a number that would
                            // be interpretted as a start offset.
                            return typeof encoding === 'string'
                                ? createBuffer(size).fill(fill, encoding)
                                : createBuffer(size).fill(fill)
                        }
                        return createBuffer(size)
                    }

                    /**
                     * Creates a new filled Buffer instance.
                     * alloc(size[, fill[, encoding]])
                     **/
                    Buffer.alloc = function (size, fill, encoding) {
                        return alloc(size, fill, encoding)
                    }

                    function allocUnsafe(size) {
                        assertSize(size)
                        return createBuffer(size < 0 ? 0 : checked(size) | 0)
                    }

                    /**
                     * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
                     * */
                    Buffer.allocUnsafe = function (size) {
                        return allocUnsafe(size)
                    }
                    /**
                     * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
                     */
                    Buffer.allocUnsafeSlow = function (size) {
                        return allocUnsafe(size)
                    }

                    function fromString(string, encoding) {
                        if (typeof encoding !== 'string' || encoding === '') {
                            encoding = 'utf8'
                        }

                        if (!Buffer.isEncoding(encoding)) {
                            throw new TypeError('Unknown encoding: ' + encoding)
                        }

                        var length = byteLength(string, encoding) | 0
                        var buf = createBuffer(length)

                        var actual = buf.write(string, encoding)

                        if (actual !== length) {
                            // Writing a hex string, for example, that contains invalid characters will
                            // cause everything after the first invalid character to be ignored. (e.g.
                            // 'abxxcd' will be treated as 'ab')
                            buf = buf.slice(0, actual)
                        }

                        return buf
                    }

                    function fromArrayLike(array) {
                        var length = array.length < 0 ? 0 : checked(array.length) | 0
                        var buf = createBuffer(length)
                        for (var i = 0; i < length; i += 1) {
                            buf[i] = array[i] & 255
                        }
                        return buf
                    }

                    function fromArrayBuffer(array, byteOffset, length) {
                        if (byteOffset < 0 || array.byteLength < byteOffset) {
                            throw new RangeError('"offset" is outside of buffer bounds')
                        }

                        if (array.byteLength < byteOffset + (length || 0)) {
                            throw new RangeError('"length" is outside of buffer bounds')
                        }

                        var buf
                        if (byteOffset === undefined && length === undefined) {
                            buf = new Uint8Array(array)
                        } else if (length === undefined) {
                            buf = new Uint8Array(array, byteOffset)
                        } else {
                            buf = new Uint8Array(array, byteOffset, length)
                        }

                        // Return an augmented `Uint8Array` instance
                        buf.__proto__ = Buffer.prototype
                        return buf
                    }

                    function fromObject(obj) {
                        if (Buffer.isBuffer(obj)) {
                            var len = checked(obj.length) | 0
                            var buf = createBuffer(len)

                            if (buf.length === 0) {
                                return buf
                            }

                            obj.copy(buf, 0, 0, len)
                            return buf
                        }

                        if (obj.length !== undefined) {
                            if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) {
                                return createBuffer(0)
                            }
                            return fromArrayLike(obj)
                        }

                        if (obj.type === 'Buffer' && Array.isArray(obj.data)) {
                            return fromArrayLike(obj.data)
                        }
                    }

                    function checked(length) {
                        // Note: cannot use `length < K_MAX_LENGTH` here because that fails when
                        // length is NaN (which is otherwise coerced to zero.)
                        if (length >= K_MAX_LENGTH) {
                            throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
                                'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes')
                        }
                        return length | 0
                    }

                    function SlowBuffer(length) {
                        if (+length != length) { // eslint-disable-line eqeqeq
                            length = 0
                        }
                        return Buffer.alloc(+length)
                    }

                    Buffer.isBuffer = function isBuffer(b) {
                        return b != null && b._isBuffer === true &&
                            b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false
                    }

                    Buffer.compare = function compare(a, b) {
                        if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength)
                        if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength)
                        if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
                            throw new TypeError(
                                'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array'
                            )
                        }

                        if (a === b) return 0

                        var x = a.length
                        var y = b.length

                        for (var i = 0, len = Math.min(x, y); i < len; ++i) {
                            if (a[i] !== b[i]) {
                                x = a[i]
                                y = b[i]
                                break
                            }
                        }

                        if (x < y) return -1
                        if (y < x) return 1
                        return 0
                    }

                    Buffer.isEncoding = function isEncoding(encoding) {
                        switch (String(encoding).toLowerCase()) {
                            case 'hex':
                            case 'utf8':
                            case 'utf-8':
                            case 'ascii':
                            case 'latin1':
                            case 'binary':
                            case 'base64':
                            case 'ucs2':
                            case 'ucs-2':
                            case 'utf16le':
                            case 'utf-16le':
                                return true
                            default:
                                return false
                        }
                    }

                    Buffer.concat = function concat(list, length) {
                        if (!Array.isArray(list)) {
                            throw new TypeError('"list" argument must be an Array of Buffers')
                        }

                        if (list.length === 0) {
                            return Buffer.alloc(0)
                        }

                        var i
                        if (length === undefined) {
                            length = 0
                            for (i = 0; i < list.length; ++i) {
                                length += list[i].length
                            }
                        }

                        var buffer = Buffer.allocUnsafe(length)
                        var pos = 0
                        for (i = 0; i < list.length; ++i) {
                            var buf = list[i]
                            if (isInstance(buf, Uint8Array)) {
                                buf = Buffer.from(buf)
                            }
                            if (!Buffer.isBuffer(buf)) {
                                throw new TypeError('"list" argument must be an Array of Buffers')
                            }
                            buf.copy(buffer, pos)
                            pos += buf.length
                        }
                        return buffer
                    }

                    function byteLength(string, encoding) {
                        if (Buffer.isBuffer(string)) {
                            return string.length
                        }
                        if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) {
                            return string.byteLength
                        }
                        if (typeof string !== 'string') {
                            throw new TypeError(
                                'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' +
                                'Received type ' + typeof string
                            )
                        }

                        var len = string.length
                        var mustMatch = (arguments.length > 2 && arguments[2] === true)
                        if (!mustMatch && len === 0) return 0

                        // Use a for loop to avoid recursion
                        var loweredCase = false
                        for (; ;) {
                            switch (encoding) {
                                case 'ascii':
                                case 'latin1':
                                case 'binary':
                                    return len
                                case 'utf8':
                                case 'utf-8':
                                    return utf8ToBytes(string).length
                                case 'ucs2':
                                case 'ucs-2':
                                case 'utf16le':
                                case 'utf-16le':
                                    return len * 2
                                case 'hex':
                                    return len >>> 1
                                case 'base64':
                                    return base64ToBytes(string).length
                                default:
                                    if (loweredCase) {
                                        return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8
                                    }
                                    encoding = ('' + encoding).toLowerCase()
                                    loweredCase = true
                            }
                        }
                    }
                    Buffer.byteLength = byteLength

                    function slowToString(encoding, start, end) {
                        var loweredCase = false

                        // No need to verify that "this.length <= MAX_UINT32" since it's a read-only
                        // property of a typed array.

                        // This behaves neither like String nor Uint8Array in that we set start/end
                        // to their upper/lower bounds if the value passed is out of range.
                        // undefined is handled specially as per ECMA-262 6th Edition,
                        // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
                        if (start === undefined || start < 0) {
                            start = 0
                        }
                        // Return early if start > this.length. Done here to prevent potential uint32
                        // coercion fail below.
                        if (start > this.length) {
                            return ''
                        }

                        if (end === undefined || end > this.length) {
                            end = this.length
                        }

                        if (end <= 0) {
                            return ''
                        }

                        // Force coersion to uint32. This will also coerce falsey/NaN values to 0.
                        end >>>= 0
                        start >>>= 0

                        if (end <= start) {
                            return ''
                        }

                        if (!encoding) encoding = 'utf8'

                        while (true) {
                            switch (encoding) {
                                case 'hex':
                                    return hexSlice(this, start, end)

                                case 'utf8':
                                case 'utf-8':
                                    return utf8Slice(this, start, end)

                                case 'ascii':
                                    return asciiSlice(this, start, end)

                                case 'latin1':
                                case 'binary':
                                    return latin1Slice(this, start, end)

                                case 'base64':
                                    return base64Slice(this, start, end)

                                case 'ucs2':
                                case 'ucs-2':
                                case 'utf16le':
                                case 'utf-16le':
                                    return utf16leSlice(this, start, end)

                                default:
                                    if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
                                    encoding = (encoding + '').toLowerCase()
                                    loweredCase = true
                            }
                        }
                    }

                    // This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package)
                    // to detect a Buffer instance. It's not possible to use `instanceof Buffer`
                    // reliably in a browserify context because there could be multiple different
                    // copies of the 'buffer' package in use. This method works even for Buffer
                    // instances that were created from another copy of the `buffer` package.
                    // See: https://github.com/feross/buffer/issues/154
                    Buffer.prototype._isBuffer = true

                    function swap(b, n, m) {
                        var i = b[n]
                        b[n] = b[m]
                        b[m] = i
                    }

                    Buffer.prototype.swap16 = function swap16() {
                        var len = this.length
                        if (len % 2 !== 0) {
                            throw new RangeError('Buffer size must be a multiple of 16-bits')
                        }
                        for (var i = 0; i < len; i += 2) {
                            swap(this, i, i + 1)
                        }
                        return this
                    }

                    Buffer.prototype.swap32 = function swap32() {
                        var len = this.length
                        if (len % 4 !== 0) {
                            throw new RangeError('Buffer size must be a multiple of 32-bits')
                        }
                        for (var i = 0; i < len; i += 4) {
                            swap(this, i, i + 3)
                            swap(this, i + 1, i + 2)
                        }
                        return this
                    }

                    Buffer.prototype.swap64 = function swap64() {
                        var len = this.length
                        if (len % 8 !== 0) {
                            throw new RangeError('Buffer size must be a multiple of 64-bits')
                        }
                        for (var i = 0; i < len; i += 8) {
                            swap(this, i, i + 7)
                            swap(this, i + 1, i + 6)
                            swap(this, i + 2, i + 5)
                            swap(this, i + 3, i + 4)
                        }
                        return this
                    }

                    Buffer.prototype.toString = function toString() {
                        var length = this.length
                        if (length === 0) return ''
                        if (arguments.length === 0) return utf8Slice(this, 0, length)
                        return slowToString.apply(this, arguments)
                    }

                    Buffer.prototype.toLocaleString = Buffer.prototype.toString

                    Buffer.prototype.equals = function equals(b) {
                        if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
                        if (this === b) return true
                        return Buffer.compare(this, b) === 0
                    }

                    Buffer.prototype.inspect = function inspect() {
                        var str = ''
                        var max = exports.INSPECT_MAX_BYTES
                        str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim()
                        if (this.length > max) str += ' ... '
                        return '<Buffer ' + str + '>'
                    }

                    Buffer.prototype.compare = function compare(target, start, end, thisStart, thisEnd) {
                        if (isInstance(target, Uint8Array)) {
                            target = Buffer.from(target, target.offset, target.byteLength)
                        }
                        if (!Buffer.isBuffer(target)) {
                            throw new TypeError(
                                'The "target" argument must be one of type Buffer or Uint8Array. ' +
                                'Received type ' + (typeof target)
                            )
                        }

                        if (start === undefined) {
                            start = 0
                        }
                        if (end === undefined) {
                            end = target ? target.length : 0
                        }
                        if (thisStart === undefined) {
                            thisStart = 0
                        }
                        if (thisEnd === undefined) {
                            thisEnd = this.length
                        }

                        if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
                            throw new RangeError('out of range index')
                        }

                        if (thisStart >= thisEnd && start >= end) {
                            return 0
                        }
                        if (thisStart >= thisEnd) {
                            return -1
                        }
                        if (start >= end) {
                            return 1
                        }

                        start >>>= 0
                        end >>>= 0
                        thisStart >>>= 0
                        thisEnd >>>= 0

                        if (this === target) return 0

                        var x = thisEnd - thisStart
                        var y = end - start
                        var len = Math.min(x, y)

                        var thisCopy = this.slice(thisStart, thisEnd)
                        var targetCopy = target.slice(start, end)

                        for (var i = 0; i < len; ++i) {
                            if (thisCopy[i] !== targetCopy[i]) {
                                x = thisCopy[i]
                                y = targetCopy[i]
                                break
                            }
                        }

                        if (x < y) return -1
                        if (y < x) return 1
                        return 0
                    }

                    // Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
                    // OR the last index of `val` in `buffer` at offset <= `byteOffset`.
                    //
                    // Arguments:
                    // - buffer - a Buffer to search
                    // - val - a string, Buffer, or number
                    // - byteOffset - an index into `buffer`; will be clamped to an int32
                    // - encoding - an optional encoding, relevant is val is a string
                    // - dir - true for indexOf, false for lastIndexOf
                    function bidirectionalIndexOf(buffer, val, byteOffset, encoding, dir) {
                        // Empty buffer means no match
                        if (buffer.length === 0) return -1

                        // Normalize byteOffset
                        if (typeof byteOffset === 'string') {
                            encoding = byteOffset
                            byteOffset = 0
                        } else if (byteOffset > 0x7fffffff) {
                            byteOffset = 0x7fffffff
                        } else if (byteOffset < -0x80000000) {
                            byteOffset = -0x80000000
                        }
                        byteOffset = +byteOffset // Coerce to Number.
                        if (numberIsNaN(byteOffset)) {
                            // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
                            byteOffset = dir ? 0 : (buffer.length - 1)
                        }

                        // Normalize byteOffset: negative offsets start from the end of the buffer
                        if (byteOffset < 0) byteOffset = buffer.length + byteOffset
                        if (byteOffset >= buffer.length) {
                            if (dir) return -1
                            else byteOffset = buffer.length - 1
                        } else if (byteOffset < 0) {
                            if (dir) byteOffset = 0
                            else return -1
                        }

                        // Normalize val
                        if (typeof val === 'string') {
                            val = Buffer.from(val, encoding)
                        }

                        // Finally, search either indexOf (if dir is true) or lastIndexOf
                        if (Buffer.isBuffer(val)) {
                            // Special case: looking for empty string/buffer always fails
                            if (val.length === 0) {
                                return -1
                            }
                            return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
                        } else if (typeof val === 'number') {
                            val = val & 0xFF // Search for a byte value [0-255]
                            if (typeof Uint8Array.prototype.indexOf === 'function') {
                                if (dir) {
                                    return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
                                } else {
                                    return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
                                }
                            }
                            return arrayIndexOf(buffer, [val], byteOffset, encoding, dir)
                        }

                        throw new TypeError('val must be string, number or Buffer')
                    }

                    function arrayIndexOf(arr, val, byteOffset, encoding, dir) {
                        var indexSize = 1
                        var arrLength = arr.length
                        var valLength = val.length

                        if (encoding !== undefined) {
                            encoding = String(encoding).toLowerCase()
                            if (encoding === 'ucs2' || encoding === 'ucs-2' ||
                                encoding === 'utf16le' || encoding === 'utf-16le') {
                                if (arr.length < 2 || val.length < 2) {
                                    return -1
                                }
                                indexSize = 2
                                arrLength /= 2
                                valLength /= 2
                                byteOffset /= 2
                            }
                        }

                        function read(buf, i) {
                            if (indexSize === 1) {
                                return buf[i]
                            } else {
                                return buf.readUInt16BE(i * indexSize)
                            }
                        }

                        var i
                        if (dir) {
                            var foundIndex = -1
                            for (i = byteOffset; i < arrLength; i++) {
                                if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
                                    if (foundIndex === -1) foundIndex = i
                                    if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
                                } else {
                                    if (foundIndex !== -1) i -= i - foundIndex
                                    foundIndex = -1
                                }
                            }
                        } else {
                            if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength
                            for (i = byteOffset; i >= 0; i--) {
                                var found = true
                                for (var j = 0; j < valLength; j++) {
                                    if (read(arr, i + j) !== read(val, j)) {
                                        found = false
                                        break
                                    }
                                }
                                if (found) return i
                            }
                        }

                        return -1
                    }

                    Buffer.prototype.includes = function includes(val, byteOffset, encoding) {
                        return this.indexOf(val, byteOffset, encoding) !== -1
                    }

                    Buffer.prototype.indexOf = function indexOf(val, byteOffset, encoding) {
                        return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
                    }

                    Buffer.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) {
                        return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
                    }

                    function hexWrite(buf, string, offset, length) {
                        offset = Number(offset) || 0
                        var remaining = buf.length - offset
                        if (!length) {
                            length = remaining
                        } else {
                            length = Number(length)
                            if (length > remaining) {
                                length = remaining
                            }
                        }

                        var strLen = string.length

                        if (length > strLen / 2) {
                            length = strLen / 2
                        }
                        for (var i = 0; i < length; ++i) {
                            var parsed = parseInt(string.substr(i * 2, 2), 16)
                            if (numberIsNaN(parsed)) return i
                            buf[offset + i] = parsed
                        }
                        return i
                    }

                    function utf8Write(buf, string, offset, length) {
                        return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
                    }

                    function asciiWrite(buf, string, offset, length) {
                        return blitBuffer(asciiToBytes(string), buf, offset, length)
                    }

                    function latin1Write(buf, string, offset, length) {
                        return asciiWrite(buf, string, offset, length)
                    }

                    function base64Write(buf, string, offset, length) {
                        return blitBuffer(base64ToBytes(string), buf, offset, length)
                    }

                    function ucs2Write(buf, string, offset, length) {
                        return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
                    }

                    Buffer.prototype.write = function write(string, offset, length, encoding) {
                        // Buffer#write(string)
                        if (offset === undefined) {
                            encoding = 'utf8'
                            length = this.length
                            offset = 0
                            // Buffer#write(string, encoding)
                        } else if (length === undefined && typeof offset === 'string') {
                            encoding = offset
                            length = this.length
                            offset = 0
                            // Buffer#write(string, offset[, length][, encoding])
                        } else if (isFinite(offset)) {
                            offset = offset >>> 0
                            if (isFinite(length)) {
                                length = length >>> 0
                                if (encoding === undefined) encoding = 'utf8'
                            } else {
                                encoding = length
                                length = undefined
                            }
                        } else {
                            throw new Error(
                                'Buffer.write(string, encoding, offset[, length]) is no longer supported'
                            )
                        }

                        var remaining = this.length - offset
                        if (length === undefined || length > remaining) length = remaining

                        if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
                            throw new RangeError('Attempt to write outside buffer bounds')
                        }

                        if (!encoding) encoding = 'utf8'

                        var loweredCase = false
                        for (; ;) {
                            switch (encoding) {
                                case 'hex':
                                    return hexWrite(this, string, offset, length)

                                case 'utf8':
                                case 'utf-8':
                                    return utf8Write(this, string, offset, length)

                                case 'ascii':
                                    return asciiWrite(this, string, offset, length)

                                case 'latin1':
                                case 'binary':
                                    return latin1Write(this, string, offset, length)

                                case 'base64':
                                    // Warning: maxLength not taken into account in base64Write
                                    return base64Write(this, string, offset, length)

                                case 'ucs2':
                                case 'ucs-2':
                                case 'utf16le':
                                case 'utf-16le':
                                    return ucs2Write(this, string, offset, length)

                                default:
                                    if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
                                    encoding = ('' + encoding).toLowerCase()
                                    loweredCase = true
                            }
                        }
                    }

                    Buffer.prototype.toJSON = function toJSON() {
                        return {
                            type: 'Buffer',
                            data: Array.prototype.slice.call(this._arr || this, 0)
                        }
                    }

                    function base64Slice(buf, start, end) {
                        if (start === 0 && end === buf.length) {
                            return base64.fromByteArray(buf)
                        } else {
                            return base64.fromByteArray(buf.slice(start, end))
                        }
                    }

                    function utf8Slice(buf, start, end) {
                        end = Math.min(buf.length, end)
                        var res = []

                        var i = start
                        while (i < end) {
                            var firstByte = buf[i]
                            var codePoint = null
                            var bytesPerSequence = (firstByte > 0xEF) ? 4
                                : (firstByte > 0xDF) ? 3
                                    : (firstByte > 0xBF) ? 2
                                        : 1

                            if (i + bytesPerSequence <= end) {
                                var secondByte, thirdByte, fourthByte, tempCodePoint

                                switch (bytesPerSequence) {
                                    case 1:
                                        if (firstByte < 0x80) {
                                            codePoint = firstByte
                                        }
                                        break
                                    case 2:
                                        secondByte = buf[i + 1]
                                        if ((secondByte & 0xC0) === 0x80) {
                                            tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
                                            if (tempCodePoint > 0x7F) {
                                                codePoint = tempCodePoint
                                            }
                                        }
                                        break
                                    case 3:
                                        secondByte = buf[i + 1]
                                        thirdByte = buf[i + 2]
                                        if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
                                            tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
                                            if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
                                                codePoint = tempCodePoint
                                            }
                                        }
                                        break
                                    case 4:
                                        secondByte = buf[i + 1]
                                        thirdByte = buf[i + 2]
                                        fourthByte = buf[i + 3]
                                        if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
                                            tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
                                            if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
                                                codePoint = tempCodePoint
                                            }
                                        }
                                }
                            }

                            if (codePoint === null) {
                                // we did not generate a valid codePoint so insert a
                                // replacement char (U+FFFD) and advance only 1 byte
                                codePoint = 0xFFFD
                                bytesPerSequence = 1
                            } else if (codePoint > 0xFFFF) {
                                // encode to utf16 (surrogate pair dance)
                                codePoint -= 0x10000
                                res.push(codePoint >>> 10 & 0x3FF | 0xD800)
                                codePoint = 0xDC00 | codePoint & 0x3FF
                            }

                            res.push(codePoint)
                            i += bytesPerSequence
                        }

                        return decodeCodePointsArray(res)
                    }

                    // Based on http://stackoverflow.com/a/22747272/680742, the browser with
                    // the lowest limit is Chrome, with 0x10000 args.
                    // We go 1 magnitude less, for safety
                    var MAX_ARGUMENTS_LENGTH = 0x1000

                    function decodeCodePointsArray(codePoints) {
                        var len = codePoints.length
                        if (len <= MAX_ARGUMENTS_LENGTH) {
                            return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
                        }

                        // Decode in chunks to avoid "call stack size exceeded".
                        var res = ''
                        var i = 0
                        while (i < len) {
                            res += String.fromCharCode.apply(
                                String,
                                codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
                            )
                        }
                        return res
                    }

                    function asciiSlice(buf, start, end) {
                        var ret = ''
                        end = Math.min(buf.length, end)

                        for (var i = start; i < end; ++i) {
                            ret += String.fromCharCode(buf[i] & 0x7F)
                        }
                        return ret
                    }

                    function latin1Slice(buf, start, end) {
                        var ret = ''
                        end = Math.min(buf.length, end)

                        for (var i = start; i < end; ++i) {
                            ret += String.fromCharCode(buf[i])
                        }
                        return ret
                    }

                    function hexSlice(buf, start, end) {
                        var len = buf.length

                        if (!start || start < 0) start = 0
                        if (!end || end < 0 || end > len) end = len

                        var out = ''
                        for (var i = start; i < end; ++i) {
                            out += toHex(buf[i])
                        }
                        return out
                    }

                    function utf16leSlice(buf, start, end) {
                        var bytes = buf.slice(start, end)
                        var res = ''
                        for (var i = 0; i < bytes.length; i += 2) {
                            res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256))
                        }
                        return res
                    }

                    Buffer.prototype.slice = function slice(start, end) {
                        var len = this.length
                        start = ~~start
                        end = end === undefined ? len : ~~end

                        if (start < 0) {
                            start += len
                            if (start < 0) start = 0
                        } else if (start > len) {
                            start = len
                        }

                        if (end < 0) {
                            end += len
                            if (end < 0) end = 0
                        } else if (end > len) {
                            end = len
                        }

                        if (end < start) end = start

                        var newBuf = this.subarray(start, end)
                        // Return an augmented `Uint8Array` instance
                        newBuf.__proto__ = Buffer.prototype
                        return newBuf
                    }

                    /*
                     * Need to make sure that buffer isn't trying to write out of bounds.
                     */
                    function checkOffset(offset, ext, length) {
                        if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
                        if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
                    }

                    Buffer.prototype.readUIntLE = function readUIntLE(offset, byteLength, noAssert) {
                        offset = offset >>> 0
                        byteLength = byteLength >>> 0
                        if (!noAssert) checkOffset(offset, byteLength, this.length)

                        var val = this[offset]
                        var mul = 1
                        var i = 0
                        while (++i < byteLength && (mul *= 0x100)) {
                            val += this[offset + i] * mul
                        }

                        return val
                    }

                    Buffer.prototype.readUIntBE = function readUIntBE(offset, byteLength, noAssert) {
                        offset = offset >>> 0
                        byteLength = byteLength >>> 0
                        if (!noAssert) {
                            checkOffset(offset, byteLength, this.length)
                        }

                        var val = this[offset + --byteLength]
                        var mul = 1
                        while (byteLength > 0 && (mul *= 0x100)) {
                            val += this[offset + --byteLength] * mul
                        }

                        return val
                    }

                    Buffer.prototype.readUInt8 = function readUInt8(offset, noAssert) {
                        offset = offset >>> 0
                        if (!noAssert) checkOffset(offset, 1, this.length)
                        return this[offset]
                    }

                    Buffer.prototype.readUInt16LE = function readUInt16LE(offset, noAssert) {
                        offset = offset >>> 0
                        if (!noAssert) checkOffset(offset, 2, this.length)
                        return this[offset] | (this[offset + 1] << 8)
                    }

                    Buffer.prototype.readUInt16BE = function readUInt16BE(offset, noAssert) {
                        offset = offset >>> 0
                        if (!noAssert) checkOffset(offset, 2, this.length)
                        return (this[offset] << 8) | this[offset + 1]
                    }

                    Buffer.prototype.readUInt32LE = function readUInt32LE(offset, noAssert) {
                        offset = offset >>> 0
                        if (!noAssert) checkOffset(offset, 4, this.length)

                        return ((this[offset]) |
                            (this[offset + 1] << 8) |
                            (this[offset + 2] << 16)) +
                            (this[offset + 3] * 0x1000000)
                    }

                    Buffer.prototype.readUInt32BE = function readUInt32BE(offset, noAssert) {
                        offset = offset >>> 0
                        if (!noAssert) checkOffset(offset, 4, this.length)

                        return (this[offset] * 0x1000000) +
                            ((this[offset + 1] << 16) |
                                (this[offset + 2] << 8) |
                                this[offset + 3])
                    }

                    Buffer.prototype.readIntLE = function readIntLE(offset, byteLength, noAssert) {
                        offset = offset >>> 0
                        byteLength = byteLength >>> 0
                        if (!noAssert) checkOffset(offset, byteLength, this.length)

                        var val = this[offset]
                        var mul = 1
                        var i = 0
                        while (++i < byteLength && (mul *= 0x100)) {
                            val += this[offset + i] * mul
                        }
                        mul *= 0x80

                        if (val >= mul) val -= Math.pow(2, 8 * byteLength)

                        return val
                    }

                    Buffer.prototype.readIntBE = function readIntBE(offset, byteLength, noAssert) {
                        offset = offset >>> 0
                        byteLength = byteLength >>> 0
                        if (!noAssert) checkOffset(offset, byteLength, this.length)

                        var i = byteLength
                        var mul = 1
                        var val = this[offset + --i]
                        while (i > 0 && (mul *= 0x100)) {
                            val += this[offset + --i] * mul
                        }
                        mul *= 0x80

                        if (val >= mul) val -= Math.pow(2, 8 * byteLength)

                        return val
                    }

                    Buffer.prototype.readInt8 = function readInt8(offset, noAssert) {
                        offset = offset >>> 0
                        if (!noAssert) checkOffset(offset, 1, this.length)
                        if (!(this[offset] & 0x80)) return (this[offset])
                        return ((0xff - this[offset] + 1) * -1)
                    }

                    Buffer.prototype.readInt16LE = function readInt16LE(offset, noAssert) {
                        offset = offset >>> 0
                        if (!noAssert) checkOffset(offset, 2, this.length)
                        var val = this[offset] | (this[offset + 1] << 8)
                        return (val & 0x8000) ? val | 0xFFFF0000 : val
                    }

                    Buffer.prototype.readInt16BE = function readInt16BE(offset, noAssert) {
                        offset = offset >>> 0
                        if (!noAssert) checkOffset(offset, 2, this.length)
                        var val = this[offset + 1] | (this[offset] << 8)
                        return (val & 0x8000) ? val | 0xFFFF0000 : val
                    }

                    Buffer.prototype.readInt32LE = function readInt32LE(offset, noAssert) {
                        offset = offset >>> 0
                        if (!noAssert) checkOffset(offset, 4, this.length)

                        return (this[offset]) |
                            (this[offset + 1] << 8) |
                            (this[offset + 2] << 16) |
                            (this[offset + 3] << 24)
                    }

                    Buffer.prototype.readInt32BE = function readInt32BE(offset, noAssert) {
                        offset = offset >>> 0
                        if (!noAssert) checkOffset(offset, 4, this.length)

                        return (this[offset] << 24) |
                            (this[offset + 1] << 16) |
                            (this[offset + 2] << 8) |
                            (this[offset + 3])
                    }

                    Buffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) {
                        offset = offset >>> 0
                        if (!noAssert) checkOffset(offset, 4, this.length)
                        return ieee754.read(this, offset, true, 23, 4)
                    }

                    Buffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) {
                        offset = offset >>> 0
                        if (!noAssert) checkOffset(offset, 4, this.length)
                        return ieee754.read(this, offset, false, 23, 4)
                    }

                    Buffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) {
                        offset = offset >>> 0
                        if (!noAssert) checkOffset(offset, 8, this.length)
                        return ieee754.read(this, offset, true, 52, 8)
                    }

                    Buffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) {
                        offset = offset >>> 0
                        if (!noAssert) checkOffset(offset, 8, this.length)
                        return ieee754.read(this, offset, false, 52, 8)
                    }

                    function checkInt(buf, value, offset, ext, max, min) {
                        if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance')
                        if (value > max || value < min) throw new RangeError('"value" argument is out of bounds')
                        if (offset + ext > buf.length) throw new RangeError('Index out of range')
                    }

                    Buffer.prototype.writeUIntLE = function writeUIntLE(value, offset, byteLength, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        byteLength = byteLength >>> 0
                        if (!noAssert) {
                            var maxBytes = Math.pow(2, 8 * byteLength) - 1
                            checkInt(this, value, offset, byteLength, maxBytes, 0)
                        }

                        var mul = 1
                        var i = 0
                        this[offset] = value & 0xFF
                        while (++i < byteLength && (mul *= 0x100)) {
                            this[offset + i] = (value / mul) & 0xFF
                        }

                        return offset + byteLength
                    }

                    Buffer.prototype.writeUIntBE = function writeUIntBE(value, offset, byteLength, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        byteLength = byteLength >>> 0
                        if (!noAssert) {
                            var maxBytes = Math.pow(2, 8 * byteLength) - 1
                            checkInt(this, value, offset, byteLength, maxBytes, 0)
                        }

                        var i = byteLength - 1
                        var mul = 1
                        this[offset + i] = value & 0xFF
                        while (--i >= 0 && (mul *= 0x100)) {
                            this[offset + i] = (value / mul) & 0xFF
                        }

                        return offset + byteLength
                    }

                    Buffer.prototype.writeUInt8 = function writeUInt8(value, offset, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)
                        this[offset] = (value & 0xff)
                        return offset + 1
                    }

                    Buffer.prototype.writeUInt16LE = function writeUInt16LE(value, offset, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
                        this[offset] = (value & 0xff)
                        this[offset + 1] = (value >>> 8)
                        return offset + 2
                    }

                    Buffer.prototype.writeUInt16BE = function writeUInt16BE(value, offset, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
                        this[offset] = (value >>> 8)
                        this[offset + 1] = (value & 0xff)
                        return offset + 2
                    }

                    Buffer.prototype.writeUInt32LE = function writeUInt32LE(value, offset, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
                        this[offset + 3] = (value >>> 24)
                        this[offset + 2] = (value >>> 16)
                        this[offset + 1] = (value >>> 8)
                        this[offset] = (value & 0xff)
                        return offset + 4
                    }

                    Buffer.prototype.writeUInt32BE = function writeUInt32BE(value, offset, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
                        this[offset] = (value >>> 24)
                        this[offset + 1] = (value >>> 16)
                        this[offset + 2] = (value >>> 8)
                        this[offset + 3] = (value & 0xff)
                        return offset + 4
                    }

                    Buffer.prototype.writeIntLE = function writeIntLE(value, offset, byteLength, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        if (!noAssert) {
                            var limit = Math.pow(2, (8 * byteLength) - 1)

                            checkInt(this, value, offset, byteLength, limit - 1, -limit)
                        }

                        var i = 0
                        var mul = 1
                        var sub = 0
                        this[offset] = value & 0xFF
                        while (++i < byteLength && (mul *= 0x100)) {
                            if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
                                sub = 1
                            }
                            this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
                        }

                        return offset + byteLength
                    }

                    Buffer.prototype.writeIntBE = function writeIntBE(value, offset, byteLength, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        if (!noAssert) {
                            var limit = Math.pow(2, (8 * byteLength) - 1)

                            checkInt(this, value, offset, byteLength, limit - 1, -limit)
                        }

                        var i = byteLength - 1
                        var mul = 1
                        var sub = 0
                        this[offset + i] = value & 0xFF
                        while (--i >= 0 && (mul *= 0x100)) {
                            if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
                                sub = 1
                            }
                            this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
                        }

                        return offset + byteLength
                    }

                    Buffer.prototype.writeInt8 = function writeInt8(value, offset, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)
                        if (value < 0) value = 0xff + value + 1
                        this[offset] = (value & 0xff)
                        return offset + 1
                    }

                    Buffer.prototype.writeInt16LE = function writeInt16LE(value, offset, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
                        this[offset] = (value & 0xff)
                        this[offset + 1] = (value >>> 8)
                        return offset + 2
                    }

                    Buffer.prototype.writeInt16BE = function writeInt16BE(value, offset, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
                        this[offset] = (value >>> 8)
                        this[offset + 1] = (value & 0xff)
                        return offset + 2
                    }

                    Buffer.prototype.writeInt32LE = function writeInt32LE(value, offset, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
                        this[offset] = (value & 0xff)
                        this[offset + 1] = (value >>> 8)
                        this[offset + 2] = (value >>> 16)
                        this[offset + 3] = (value >>> 24)
                        return offset + 4
                    }

                    Buffer.prototype.writeInt32BE = function writeInt32BE(value, offset, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
                        if (value < 0) value = 0xffffffff + value + 1
                        this[offset] = (value >>> 24)
                        this[offset + 1] = (value >>> 16)
                        this[offset + 2] = (value >>> 8)
                        this[offset + 3] = (value & 0xff)
                        return offset + 4
                    }

                    function checkIEEE754(buf, value, offset, ext, max, min) {
                        if (offset + ext > buf.length) throw new RangeError('Index out of range')
                        if (offset < 0) throw new RangeError('Index out of range')
                    }

                    function writeFloat(buf, value, offset, littleEndian, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        if (!noAssert) {
                            checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
                        }
                        ieee754.write(buf, value, offset, littleEndian, 23, 4)
                        return offset + 4
                    }

                    Buffer.prototype.writeFloatLE = function writeFloatLE(value, offset, noAssert) {
                        return writeFloat(this, value, offset, true, noAssert)
                    }

                    Buffer.prototype.writeFloatBE = function writeFloatBE(value, offset, noAssert) {
                        return writeFloat(this, value, offset, false, noAssert)
                    }

                    function writeDouble(buf, value, offset, littleEndian, noAssert) {
                        value = +value
                        offset = offset >>> 0
                        if (!noAssert) {
                            checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
                        }
                        ieee754.write(buf, value, offset, littleEndian, 52, 8)
                        return offset + 8
                    }

                    Buffer.prototype.writeDoubleLE = function writeDoubleLE(value, offset, noAssert) {
                        return writeDouble(this, value, offset, true, noAssert)
                    }

                    Buffer.prototype.writeDoubleBE = function writeDoubleBE(value, offset, noAssert) {
                        return writeDouble(this, value, offset, false, noAssert)
                    }

                    // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
                    Buffer.prototype.copy = function copy(target, targetStart, start, end) {
                        if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer')
                        if (!start) start = 0
                        if (!end && end !== 0) end = this.length
                        if (targetStart >= target.length) targetStart = target.length
                        if (!targetStart) targetStart = 0
                        if (end > 0 && end < start) end = start

                        // Copy 0 bytes; we're done
                        if (end === start) return 0
                        if (target.length === 0 || this.length === 0) return 0

                        // Fatal error conditions
                        if (targetStart < 0) {
                            throw new RangeError('targetStart out of bounds')
                        }
                        if (start < 0 || start >= this.length) throw new RangeError('Index out of range')
                        if (end < 0) throw new RangeError('sourceEnd out of bounds')

                        // Are we oob?
                        if (end > this.length) end = this.length
                        if (target.length - targetStart < end - start) {
                            end = target.length - targetStart + start
                        }

                        var len = end - start

                        if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') {
                            // Use built-in when available, missing from IE11
                            this.copyWithin(targetStart, start, end)
                        } else if (this === target && start < targetStart && targetStart < end) {
                            // descending copy from end
                            for (var i = len - 1; i >= 0; --i) {
                                target[i + targetStart] = this[i + start]
                            }
                        } else {
                            Uint8Array.prototype.set.call(
                                target,
                                this.subarray(start, end),
                                targetStart
                            )
                        }

                        return len
                    }

                    // Usage:
                    //    buffer.fill(number[, offset[, end]])
                    //    buffer.fill(buffer[, offset[, end]])
                    //    buffer.fill(string[, offset[, end]][, encoding])
                    Buffer.prototype.fill = function fill(val, start, end, encoding) {
                        // Handle string cases:
                        if (typeof val === 'string') {
                            if (typeof start === 'string') {
                                encoding = start
                                start = 0
                                end = this.length
                            } else if (typeof end === 'string') {
                                encoding = end
                                end = this.length
                            }
                            if (encoding !== undefined && typeof encoding !== 'string') {
                                throw new TypeError('encoding must be a string')
                            }
                            if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
                                throw new TypeError('Unknown encoding: ' + encoding)
                            }
                            if (val.length === 1) {
                                var code = val.charCodeAt(0)
                                if ((encoding === 'utf8' && code < 128) ||
                                    encoding === 'latin1') {
                                    // Fast path: If `val` fits into a single byte, use that numeric value.
                                    val = code
                                }
                            }
                        } else if (typeof val === 'number') {
                            val = val & 255
                        }

                        // Invalid ranges are not set to a default, so can range check early.
                        if (start < 0 || this.length < start || this.length < end) {
                            throw new RangeError('Out of range index')
                        }

                        if (end <= start) {
                            return this
                        }

                        start = start >>> 0
                        end = end === undefined ? this.length : end >>> 0

                        if (!val) val = 0

                        var i
                        if (typeof val === 'number') {
                            for (i = start; i < end; ++i) {
                                this[i] = val
                            }
                        } else {
                            var bytes = Buffer.isBuffer(val)
                                ? val
                                : Buffer.from(val, encoding)
                            var len = bytes.length
                            if (len === 0) {
                                throw new TypeError('The value "' + val +
                                    '" is invalid for argument "value"')
                            }
                            for (i = 0; i < end - start; ++i) {
                                this[i + start] = bytes[i % len]
                            }
                        }

                        return this
                    }

                    // HELPER FUNCTIONS
                    // ================

                    var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g

                    function base64clean(str) {
                        // Node takes equal signs as end of the Base64 encoding
                        str = str.split('=')[0]
                        // Node strips out invalid characters like \n and \t from the string, base64-js does not
                        str = str.trim().replace(INVALID_BASE64_RE, '')
                        // Node converts strings with length < 2 to ''
                        if (str.length < 2) return ''
                        // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
                        while (str.length % 4 !== 0) {
                            str = str + '='
                        }
                        return str
                    }

                    function toHex(n) {
                        if (n < 16) return '0' + n.toString(16)
                        return n.toString(16)
                    }

                    function utf8ToBytes(string, units) {
                        units = units || Infinity
                        var codePoint
                        var length = string.length
                        var leadSurrogate = null
                        var bytes = []

                        for (var i = 0; i < length; ++i) {
                            codePoint = string.charCodeAt(i)

                            // is surrogate component
                            if (codePoint > 0xD7FF && codePoint < 0xE000) {
                                // last char was a lead
                                if (!leadSurrogate) {
                                    // no lead yet
                                    if (codePoint > 0xDBFF) {
                                        // unexpected trail
                                        if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
                                        continue
                                    } else if (i + 1 === length) {
                                        // unpaired lead
                                        if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
                                        continue
                                    }

                                    // valid lead
                                    leadSurrogate = codePoint

                                    continue
                                }

                                // 2 leads in a row
                                if (codePoint < 0xDC00) {
                                    if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
                                    leadSurrogate = codePoint
                                    continue
                                }

                                // valid surrogate pair
                                codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
                            } else if (leadSurrogate) {
                                // valid bmp char, but last char was a lead
                                if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
                            }

                            leadSurrogate = null

                            // encode utf8
                            if (codePoint < 0x80) {
                                if ((units -= 1) < 0) break
                                bytes.push(codePoint)
                            } else if (codePoint < 0x800) {
                                if ((units -= 2) < 0) break
                                bytes.push(
                                    codePoint >> 0x6 | 0xC0,
                                    codePoint & 0x3F | 0x80
                                )
                            } else if (codePoint < 0x10000) {
                                if ((units -= 3) < 0) break
                                bytes.push(
                                    codePoint >> 0xC | 0xE0,
                                    codePoint >> 0x6 & 0x3F | 0x80,
                                    codePoint & 0x3F | 0x80
                                )
                            } else if (codePoint < 0x110000) {
                                if ((units -= 4) < 0) break
                                bytes.push(
                                    codePoint >> 0x12 | 0xF0,
                                    codePoint >> 0xC & 0x3F | 0x80,
                                    codePoint >> 0x6 & 0x3F | 0x80,
                                    codePoint & 0x3F | 0x80
                                )
                            } else {
                                throw new Error('Invalid code point')
                            }
                        }

                        return bytes
                    }

                    function asciiToBytes(str) {
                        var byteArray = []
                        for (var i = 0; i < str.length; ++i) {
                            // Node's code seems to be doing this and not & 0x7F..
                            byteArray.push(str.charCodeAt(i) & 0xFF)
                        }
                        return byteArray
                    }

                    function utf16leToBytes(str, units) {
                        var c, hi, lo
                        var byteArray = []
                        for (var i = 0; i < str.length; ++i) {
                            if ((units -= 2) < 0) break

                            c = str.charCodeAt(i)
                            hi = c >> 8
                            lo = c % 256
                            byteArray.push(lo)
                            byteArray.push(hi)
                        }

                        return byteArray
                    }

                    function base64ToBytes(str) {
                        return base64.toByteArray(base64clean(str))
                    }

                    function blitBuffer(src, dst, offset, length) {
                        for (var i = 0; i < length; ++i) {
                            if ((i + offset >= dst.length) || (i >= src.length)) break
                            dst[i + offset] = src[i]
                        }
                        return i
                    }

                    // ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass
                    // the `instanceof` check but they should be treated as of that type.
                    // See: https://github.com/feross/buffer/issues/166
                    function isInstance(obj, type) {
                        return obj instanceof type ||
                            (obj != null && obj.constructor != null && obj.constructor.name != null &&
                                obj.constructor.name === type.name)
                    }
                    function numberIsNaN(obj) {
                        // For IE11 support
                        return obj !== obj // eslint-disable-line no-self-compare
                    }

                }).call(this)
            }).call(this, require("buffer").Buffer)
        }, { "base64-js": 1, "buffer": 3, "ieee754": 5 }], 4: [function (require, module, exports) {
            // Copyright Joyent, Inc. and other Node contributors.
            //
            // Permission is hereby granted, free of charge, to any person obtaining a
            // copy of this software and associated documentation files (the
            // "Software"), to deal in the Software without restriction, including
            // without limitation the rights to use, copy, modify, merge, publish,
            // distribute, sublicense, and/or sell copies of the Software, and to permit
            // persons to whom the Software is furnished to do so, subject to the
            // following conditions:
            //
            // The above copyright notice and this permission notice shall be included
            // in all copies or substantial portions of the Software.
            //
            // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
            // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
            // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
            // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
            // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
            // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
            // USE OR OTHER DEALINGS IN THE SOFTWARE.

            'use strict';

            var R = typeof Reflect === 'object' ? Reflect : null
            var ReflectApply = R && typeof R.apply === 'function'
                ? R.apply
                : function ReflectApply(target, receiver, args) {
                    return Function.prototype.apply.call(target, receiver, args);
                }

            var ReflectOwnKeys
            if (R && typeof R.ownKeys === 'function') {
                ReflectOwnKeys = R.ownKeys
            } else if (Object.getOwnPropertySymbols) {
                ReflectOwnKeys = function ReflectOwnKeys(target) {
                    return Object.getOwnPropertyNames(target)
                        .concat(Object.getOwnPropertySymbols(target));
                };
            } else {
                ReflectOwnKeys = function ReflectOwnKeys(target) {
                    return Object.getOwnPropertyNames(target);
                };
            }

            function ProcessEmitWarning(warning) {
                if (console && console.warn) console.warn(warning);
            }

            var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
                return value !== value;
            }

            function EventEmitter() {
                EventEmitter.init.call(this);
            }
            module.exports = EventEmitter;
            module.exports.once = once;

            // Backwards-compat with node 0.10.x
            EventEmitter.EventEmitter = EventEmitter;

            EventEmitter.prototype._events = undefined;
            EventEmitter.prototype._eventsCount = 0;
            EventEmitter.prototype._maxListeners = undefined;

            // By default EventEmitters will print a warning if more than 10 listeners are
            // added to it. This is a useful default which helps finding memory leaks.
            var defaultMaxListeners = 10;

            function checkListener(listener) {
                if (typeof listener !== 'function') {
                    throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
                }
            }

            Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
                enumerable: true,
                get: function () {
                    return defaultMaxListeners;
                },
                set: function (arg) {
                    if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
                        throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.');
                    }
                    defaultMaxListeners = arg;
                }
            });

            EventEmitter.init = function () {

                if (this._events === undefined ||
                    this._events === Object.getPrototypeOf(this)._events) {
                    this._events = Object.create(null);
                    this._eventsCount = 0;
                }

                this._maxListeners = this._maxListeners || undefined;
            };

            // Obviously not all Emitters should be limited to 10. This function allows
            // that to be increased. Set to zero for unlimited.
            EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
                if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
                    throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
                }
                this._maxListeners = n;
                return this;
            };

            function _getMaxListeners(that) {
                if (that._maxListeners === undefined)
                    return EventEmitter.defaultMaxListeners;
                return that._maxListeners;
            }

            EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
                return _getMaxListeners(this);
            };

            EventEmitter.prototype.emit = function emit(type) {
                var args = [];
                for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
                var doError = (type === 'error');

                var events = this._events;
                if (events !== undefined)
                    doError = (doError && events.error === undefined);
                else if (!doError)
                    return false;

                // If there is no 'error' event listener then throw.
                if (doError) {
                    var er;
                    if (args.length > 0)
                        er = args[0];
                    if (er instanceof Error) {
                        // Note: The comments on the `throw` lines are intentional, they show
                        // up in Node's output if this results in an unhandled exception.
                        throw er; // Unhandled 'error' event
                    }
                    // At least give some kind of context to the user
                    var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
                    err.context = er;
                    throw err; // Unhandled 'error' event
                }

                var handler = events[type];

                if (handler === undefined)
                    return false;

                if (typeof handler === 'function') {
                    ReflectApply(handler, this, args);
                } else {
                    var len = handler.length;
                    var listeners = arrayClone(handler, len);
                    for (var i = 0; i < len; ++i)
                        ReflectApply(listeners[i], this, args);
                }

                return true;
            };

            function _addListener(target, type, listener, prepend) {
                var m;
                var events;
                var existing;

                checkListener(listener);

                events = target._events;
                if (events === undefined) {
                    events = target._events = Object.create(null);
                    target._eventsCount = 0;
                } else {
                    // To avoid recursion in the case that type === "newListener"! Before
                    // adding it to the listeners, first emit "newListener".
                    if (events.newListener !== undefined) {
                        target.emit('newListener', type,
                            listener.listener ? listener.listener : listener);

                        // Re-assign `events` because a newListener handler could have caused the
                        // this._events to be assigned to a new object
                        events = target._events;
                    }
                    existing = events[type];
                }

                if (existing === undefined) {
                    // Optimize the case of one listener. Don't need the extra array object.
                    existing = events[type] = listener;
                    ++target._eventsCount;
                } else {
                    if (typeof existing === 'function') {
                        // Adding the second element, need to change to array.
                        existing = events[type] =
                            prepend ? [listener, existing] : [existing, listener];
                        // If we've already got an array, just append.
                    } else if (prepend) {
                        existing.unshift(listener);
                    } else {
                        existing.push(listener);
                    }

                    // Check for listener leak
                    m = _getMaxListeners(target);
                    if (m > 0 && existing.length > m && !existing.warned) {
                        existing.warned = true;
                        // No error code for this since it is a Warning
                        // eslint-disable-next-line no-restricted-syntax
                        var w = new Error('Possible EventEmitter memory leak detected. ' +
                            existing.length + ' ' + String(type) + ' listeners ' +
                            'added. Use emitter.setMaxListeners() to ' +
                            'increase limit');
                        w.name = 'MaxListenersExceededWarning';
                        w.emitter = target;
                        w.type = type;
                        w.count = existing.length;
                        ProcessEmitWarning(w);
                    }
                }

                return target;
            }

            EventEmitter.prototype.addListener = function addListener(type, listener) {
                return _addListener(this, type, listener, false);
            };

            EventEmitter.prototype.on = EventEmitter.prototype.addListener;

            EventEmitter.prototype.prependListener =
                function prependListener(type, listener) {
                    return _addListener(this, type, listener, true);
                };

            function onceWrapper() {
                if (!this.fired) {
                    this.target.removeListener(this.type, this.wrapFn);
                    this.fired = true;
                    if (arguments.length === 0)
                        return this.listener.call(this.target);
                    return this.listener.apply(this.target, arguments);
                }
            }

            function _onceWrap(target, type, listener) {
                var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
                var wrapped = onceWrapper.bind(state);
                wrapped.listener = listener;
                state.wrapFn = wrapped;
                return wrapped;
            }

            EventEmitter.prototype.once = function once(type, listener) {
                checkListener(listener);
                this.on(type, _onceWrap(this, type, listener));
                return this;
            };

            EventEmitter.prototype.prependOnceListener =
                function prependOnceListener(type, listener) {
                    checkListener(listener);
                    this.prependListener(type, _onceWrap(this, type, listener));
                    return this;
                };

            // Emits a 'removeListener' event if and only if the listener was removed.
            EventEmitter.prototype.removeListener =
                function removeListener(type, listener) {
                    var list, events, position, i, originalListener;

                    checkListener(listener);

                    events = this._events;
                    if (events === undefined)
                        return this;

                    list = events[type];
                    if (list === undefined)
                        return this;

                    if (list === listener || list.listener === listener) {
                        if (--this._eventsCount === 0)
                            this._events = Object.create(null);
                        else {
                            delete events[type];
                            if (events.removeListener)
                                this.emit('removeListener', type, list.listener || listener);
                        }
                    } else if (typeof list !== 'function') {
                        position = -1;

                        for (i = list.length - 1; i >= 0; i--) {
                            if (list[i] === listener || list[i].listener === listener) {
                                originalListener = list[i].listener;
                                position = i;
                                break;
                            }
                        }

                        if (position < 0)
                            return this;

                        if (position === 0)
                            list.shift();
                        else {
                            spliceOne(list, position);
                        }

                        if (list.length === 1)
                            events[type] = list[0];

                        if (events.removeListener !== undefined)
                            this.emit('removeListener', type, originalListener || listener);
                    }

                    return this;
                };

            EventEmitter.prototype.off = EventEmitter.prototype.removeListener;

            EventEmitter.prototype.removeAllListeners =
                function removeAllListeners(type) {
                    var listeners, events, i;

                    events = this._events;
                    if (events === undefined)
                        return this;

                    // not listening for removeListener, no need to emit
                    if (events.removeListener === undefined) {
                        if (arguments.length === 0) {
                            this._events = Object.create(null);
                            this._eventsCount = 0;
                        } else if (events[type] !== undefined) {
                            if (--this._eventsCount === 0)
                                this._events = Object.create(null);
                            else
                                delete events[type];
                        }
                        return this;
                    }

                    // emit removeListener for all listeners on all events
                    if (arguments.length === 0) {
                        var keys = Object.keys(events);
                        var key;
                        for (i = 0; i < keys.length; ++i) {
                            key = keys[i];
                            if (key === 'removeListener') continue;
                            this.removeAllListeners(key);
                        }
                        this.removeAllListeners('removeListener');
                        this._events = Object.create(null);
                        this._eventsCount = 0;
                        return this;
                    }

                    listeners = events[type];

                    if (typeof listeners === 'function') {
                        this.removeListener(type, listeners);
                    } else if (listeners !== undefined) {
                        // LIFO order
                        for (i = listeners.length - 1; i >= 0; i--) {
                            this.removeListener(type, listeners[i]);
                        }
                    }

                    return this;
                };

            function _listeners(target, type, unwrap) {
                var events = target._events;

                if (events === undefined)
                    return [];

                var evlistener = events[type];
                if (evlistener === undefined)
                    return [];

                if (typeof evlistener === 'function')
                    return unwrap ? [evlistener.listener || evlistener] : [evlistener];

                return unwrap ?
                    unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
            }

            EventEmitter.prototype.listeners = function listeners(type) {
                return _listeners(this, type, true);
            };

            EventEmitter.prototype.rawListeners = function rawListeners(type) {
                return _listeners(this, type, false);
            };

            EventEmitter.listenerCount = function (emitter, type) {
                if (typeof emitter.listenerCount === 'function') {
                    return emitter.listenerCount(type);
                } else {
                    return listenerCount.call(emitter, type);
                }
            };

            EventEmitter.prototype.listenerCount = listenerCount;
            function listenerCount(type) {
                var events = this._events;

                if (events !== undefined) {
                    var evlistener = events[type];

                    if (typeof evlistener === 'function') {
                        return 1;
                    } else if (evlistener !== undefined) {
                        return evlistener.length;
                    }
                }

                return 0;
            }

            EventEmitter.prototype.eventNames = function eventNames() {
                return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
            };

            function arrayClone(arr, n) {
                var copy = new Array(n);
                for (var i = 0; i < n; ++i)
                    copy[i] = arr[i];
                return copy;
            }

            function spliceOne(list, index) {
                for (; index + 1 < list.length; index++)
                    list[index] = list[index + 1];
                list.pop();
            }

            function unwrapListeners(arr) {
                var ret = new Array(arr.length);
                for (var i = 0; i < ret.length; ++i) {
                    ret[i] = arr[i].listener || arr[i];
                }
                return ret;
            }

            function once(emitter, name) {
                return new Promise(function (resolve, reject) {
                    function errorListener(err) {
                        emitter.removeListener(name, resolver);
                        reject(err);
                    }

                    function resolver() {
                        if (typeof emitter.removeListener === 'function') {
                            emitter.removeListener('error', errorListener);
                        }
                        resolve([].slice.call(arguments));
                    };

                    eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
                    if (name !== 'error') {
                        addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });
                    }
                });
            }

            function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
                if (typeof emitter.on === 'function') {
                    eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
                }
            }

            function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
                if (typeof emitter.on === 'function') {
                    if (flags.once) {
                        emitter.once(name, listener);
                    } else {
                        emitter.on(name, listener);
                    }
                } else if (typeof emitter.addEventListener === 'function') {
                    // EventTarget does not have `error` event semantics like Node
                    // EventEmitters, we do not listen for `error` events here.
                    emitter.addEventListener(name, function wrapListener(arg) {
                        // IE does not have builtin `{ once: true }` support so we
                        // have to do it manually.
                        if (flags.once) {
                            emitter.removeEventListener(name, wrapListener);
                        }
                        listener(arg);
                    });
                } else {
                    throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter);
                }
            }

        }, {}], 5: [function (require, module, exports) {
            /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
            exports.read = function (buffer, offset, isLE, mLen, nBytes) {
                var e, m
                var eLen = (nBytes * 8) - mLen - 1
                var eMax = (1 << eLen) - 1
                var eBias = eMax >> 1
                var nBits = -7
                var i = isLE ? (nBytes - 1) : 0
                var d = isLE ? -1 : 1
                var s = buffer[offset + i]

                i += d

                e = s & ((1 << (-nBits)) - 1)
                s >>= (-nBits)
                nBits += eLen
                for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) { }

                m = e & ((1 << (-nBits)) - 1)
                e >>= (-nBits)
                nBits += mLen
                for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) { }

                if (e === 0) {
                    e = 1 - eBias
                } else if (e === eMax) {
                    return m ? NaN : ((s ? -1 : 1) * Infinity)
                } else {
                    m = m + Math.pow(2, mLen)
                    e = e - eBias
                }
                return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
            }

            exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
                var e, m, c
                var eLen = (nBytes * 8) - mLen - 1
                var eMax = (1 << eLen) - 1
                var eBias = eMax >> 1
                var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
                var i = isLE ? 0 : (nBytes - 1)
                var d = isLE ? 1 : -1
                var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0

                value = Math.abs(value)

                if (isNaN(value) || value === Infinity) {
                    m = isNaN(value) ? 1 : 0
                    e = eMax
                } else {
                    e = Math.floor(Math.log(value) / Math.LN2)
                    if (value * (c = Math.pow(2, -e)) < 1) {
                        e--
                        c *= 2
                    }
                    if (e + eBias >= 1) {
                        value += rt / c
                    } else {
                        value += rt * Math.pow(2, 1 - eBias)
                    }
                    if (value * c >= 2) {
                        e++
                        c /= 2
                    }

                    if (e + eBias >= eMax) {
                        m = 0
                        e = eMax
                    } else if (e + eBias >= 1) {
                        m = ((value * c) - 1) * Math.pow(2, mLen)
                        e = e + eBias
                    } else {
                        m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
                        e = 0
                    }
                }

                for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) { }

                e = (e << mLen) | m
                eLen += mLen
                for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) { }

                buffer[offset + i - d] |= s * 128
            }

        }, {}], 6: [function (require, module, exports) {
            if (typeof Object.create === 'function') {
                // implementation from standard node.js 'util' module
                module.exports = function inherits(ctor, superCtor) {
                    if (superCtor) {
                        ctor.super_ = superCtor
                        ctor.prototype = Object.create(superCtor.prototype, {
                            constructor: {
                                value: ctor,
                                enumerable: false,
                                writable: true,
                                configurable: true
                            }
                        })
                    }
                };
            } else {
                // old school shim for old browsers
                module.exports = function inherits(ctor, superCtor) {
                    if (superCtor) {
                        ctor.super_ = superCtor
                        var TempCtor = function () { }
                        TempCtor.prototype = superCtor.prototype
                        ctor.prototype = new TempCtor()
                        ctor.prototype.constructor = ctor
                    }
                }
            }

        }, {}], 7: [function (require, module, exports) {
            // shim for using process in browser
            var process = module.exports = {};

            // cached from whatever global is present so that test runners that stub it
            // don't break things.  But we need to wrap it in a try catch in case it is
            // wrapped in strict mode code which doesn't define any globals.  It's inside a
            // function because try/catches deoptimize in certain engines.

            var cachedSetTimeout;
            var cachedClearTimeout;

            function defaultSetTimout() {
                throw new Error('setTimeout has not been defined');
            }
            function defaultClearTimeout() {
                throw new Error('clearTimeout has not been defined');
            }
            (function () {
                try {
                    if (typeof setTimeout === 'function') {
                        cachedSetTimeout = setTimeout;
                    } else {
                        cachedSetTimeout = defaultSetTimout;
                    }
                } catch (e) {
                    cachedSetTimeout = defaultSetTimout;
                }
                try {
                    if (typeof clearTimeout === 'function') {
                        cachedClearTimeout = clearTimeout;
                    } else {
                        cachedClearTimeout = defaultClearTimeout;
                    }
                } catch (e) {
                    cachedClearTimeout = defaultClearTimeout;
                }
            }())
            function runTimeout(fun) {
                if (cachedSetTimeout === setTimeout) {
                    //normal enviroments in sane situations
                    return setTimeout(fun, 0);
                }
                // if setTimeout wasn't available but was latter defined
                if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
                    cachedSetTimeout = setTimeout;
                    return setTimeout(fun, 0);
                }
                try {
                    // when when somebody has screwed with setTimeout but no I.E. maddness
                    return cachedSetTimeout(fun, 0);
                } catch (e) {
                    try {
                        // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
                        return cachedSetTimeout.call(null, fun, 0);
                    } catch (e) {
                        // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
                        return cachedSetTimeout.call(this, fun, 0);
                    }
                }


            }
            function runClearTimeout(marker) {
                if (cachedClearTimeout === clearTimeout) {
                    //normal enviroments in sane situations
                    return clearTimeout(marker);
                }
                // if clearTimeout wasn't available but was latter defined
                if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
                    cachedClearTimeout = clearTimeout;
                    return clearTimeout(marker);
                }
                try {
                    // when when somebody has screwed with setTimeout but no I.E. maddness
                    return cachedClearTimeout(marker);
                } catch (e) {
                    try {
                        // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
                        return cachedClearTimeout.call(null, marker);
                    } catch (e) {
                        // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
                        // Some versions of I.E. have different rules for clearTimeout vs setTimeout
                        return cachedClearTimeout.call(this, marker);
                    }
                }



            }
            var queue = [];
            var draining = false;
            var currentQueue;
            var queueIndex = -1;

            function cleanUpNextTick() {
                if (!draining || !currentQueue) {
                    return;
                }
                draining = false;
                if (currentQueue.length) {
                    queue = currentQueue.concat(queue);
                } else {
                    queueIndex = -1;
                }
                if (queue.length) {
                    drainQueue();
                }
            }

            function drainQueue() {
                if (draining) {
                    return;
                }
                var timeout = runTimeout(cleanUpNextTick);
                draining = true;

                var len = queue.length;
                while (len) {
                    currentQueue = queue;
                    queue = [];
                    while (++queueIndex < len) {
                        if (currentQueue) {
                            currentQueue[queueIndex].run();
                        }
                    }
                    queueIndex = -1;
                    len = queue.length;
                }
                currentQueue = null;
                draining = false;
                runClearTimeout(timeout);
            }

            process.nextTick = function (fun) {
                var args = new Array(arguments.length - 1);
                if (arguments.length > 1) {
                    for (var i = 1; i < arguments.length; i++) {
                        args[i - 1] = arguments[i];
                    }
                }
                queue.push(new Item(fun, args));
                if (queue.length === 1 && !draining) {
                    runTimeout(drainQueue);
                }
            };

            // v8 likes predictible objects
            function Item(fun, array) {
                this.fun = fun;
                this.array = array;
            }
            Item.prototype.run = function () {
                this.fun.apply(null, this.array);
            };
            process.title = 'browser';
            process.browser = true;
            process.env = {};
            process.argv = [];
            process.version = ''; // empty string to avoid regexp issues
            process.versions = {};

            function noop() { }

            process.on = noop;
            process.addListener = noop;
            process.once = noop;
            process.off = noop;
            process.removeListener = noop;
            process.removeAllListeners = noop;
            process.emit = noop;
            process.prependListener = noop;
            process.prependOnceListener = noop;

            process.listeners = function (name) { return [] }

            process.binding = function (name) {
                throw new Error('process.binding is not supported');
            };

            process.cwd = function () { return '/' };
            process.chdir = function (dir) {
                throw new Error('process.chdir is not supported');
            };
            process.umask = function () { return 0; };

        }, {}], 8: [function (require, module, exports) {
            /*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
            /* eslint-disable node/no-deprecated-api */
            var buffer = require('buffer')
            var Buffer = buffer.Buffer

            // alternative to using Object.keys for old browsers
            function copyProps(src, dst) {
                for (var key in src) {
                    dst[key] = src[key]
                }
            }
            if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {
                module.exports = buffer
            } else {
                // Copy properties from require('buffer')
                copyProps(buffer, exports)
                exports.Buffer = SafeBuffer
            }

            function SafeBuffer(arg, encodingOrOffset, length) {
                return Buffer(arg, encodingOrOffset, length)
            }

            SafeBuffer.prototype = Object.create(Buffer.prototype)

            // Copy static methods from Buffer
            copyProps(Buffer, SafeBuffer)

            SafeBuffer.from = function (arg, encodingOrOffset, length) {
                if (typeof arg === 'number') {
                    throw new TypeError('Argument must not be a number')
                }
                return Buffer(arg, encodingOrOffset, length)
            }

            SafeBuffer.alloc = function (size, fill, encoding) {
                if (typeof size !== 'number') {
                    throw new TypeError('Argument must be a number')
                }
                var buf = Buffer(size)
                if (fill !== undefined) {
                    if (typeof encoding === 'string') {
                        buf.fill(fill, encoding)
                    } else {
                        buf.fill(fill)
                    }
                } else {
                    buf.fill(0)
                }
                return buf
            }

            SafeBuffer.allocUnsafe = function (size) {
                if (typeof size !== 'number') {
                    throw new TypeError('Argument must be a number')
                }
                return Buffer(size)
            }

            SafeBuffer.allocUnsafeSlow = function (size) {
                if (typeof size !== 'number') {
                    throw new TypeError('Argument must be a number')
                }
                return buffer.SlowBuffer(size)
            }

        }, { "buffer": 3 }], 9: [function (require, module, exports) {
            // Copyright Joyent, Inc. and other Node contributors.
            //
            // Permission is hereby granted, free of charge, to any person obtaining a
            // copy of this software and associated documentation files (the
            // "Software"), to deal in the Software without restriction, including
            // without limitation the rights to use, copy, modify, merge, publish,
            // distribute, sublicense, and/or sell copies of the Software, and to permit
            // persons to whom the Software is furnished to do so, subject to the
            // following conditions:
            //
            // The above copyright notice and this permission notice shall be included
            // in all copies or substantial portions of the Software.
            //
            // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
            // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
            // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
            // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
            // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
            // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
            // USE OR OTHER DEALINGS IN THE SOFTWARE.

            module.exports = Stream;

            var EE = require('events').EventEmitter;
            var inherits = require('inherits');

            inherits(Stream, EE);
            Stream.Readable = require('readable-stream/lib/_stream_readable.js');
            Stream.Writable = require('readable-stream/lib/_stream_writable.js');
            Stream.Duplex = require('readable-stream/lib/_stream_duplex.js');
            Stream.Transform = require('readable-stream/lib/_stream_transform.js');
            Stream.PassThrough = require('readable-stream/lib/_stream_passthrough.js');
            Stream.finished = require('readable-stream/lib/internal/streams/end-of-stream.js')
            Stream.pipeline = require('readable-stream/lib/internal/streams/pipeline.js')

            // Backwards-compat with node 0.4.x
            Stream.Stream = Stream;



            // old-style streams.  Note that the pipe method (the only relevant
            // part of this class) is overridden in the Readable class.

            function Stream() {
                EE.call(this);
            }

            Stream.prototype.pipe = function (dest, options) {
                var source = this;

                function ondata(chunk) {
                    if (dest.writable) {
                        if (false === dest.write(chunk) && source.pause) {
                            source.pause();
                        }
                    }
                }

                source.on('data', ondata);

                function ondrain() {
                    if (source.readable && source.resume) {
                        source.resume();
                    }
                }

                dest.on('drain', ondrain);

                // If the 'end' option is not supplied, dest.end() will be called when
                // source gets the 'end' or 'close' events.  Only dest.end() once.
                if (!dest._isStdio && (!options || options.end !== false)) {
                    source.on('end', onend);
                    source.on('close', onclose);
                }

                var didOnEnd = false;
                function onend() {
                    if (didOnEnd) return;
                    didOnEnd = true;

                    dest.end();
                }


                function onclose() {
                    if (didOnEnd) return;
                    didOnEnd = true;

                    if (typeof dest.destroy === 'function') dest.destroy();
                }

                // don't leave dangling pipes when there are errors.
                function onerror(er) {
                    cleanup();
                    if (EE.listenerCount(this, 'error') === 0) {
                        throw er; // Unhandled stream error in pipe.
                    }
                }

                source.on('error', onerror);
                dest.on('error', onerror);

                // remove all the event listeners that were added.
                function cleanup() {
                    source.removeListener('data', ondata);
                    dest.removeListener('drain', ondrain);

                    source.removeListener('end', onend);
                    source.removeListener('close', onclose);

                    source.removeListener('error', onerror);
                    dest.removeListener('error', onerror);

                    source.removeListener('end', cleanup);
                    source.removeListener('close', cleanup);

                    dest.removeListener('close', cleanup);
                }

                source.on('end', cleanup);
                source.on('close', cleanup);

                dest.on('close', cleanup);

                dest.emit('pipe', source);

                // Allow for unix-like usage: A.pipe(B).pipe(C)
                return dest;
            };

        }, { "events": 4, "inherits": 6, "readable-stream/lib/_stream_duplex.js": 11, "readable-stream/lib/_stream_passthrough.js": 12, "readable-stream/lib/_stream_readable.js": 13, "readable-stream/lib/_stream_transform.js": 14, "readable-stream/lib/_stream_writable.js": 15, "readable-stream/lib/internal/streams/end-of-stream.js": 19, "readable-stream/lib/internal/streams/pipeline.js": 21 }], 10: [function (require, module, exports) {
            'use strict';

            function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }

            var codes = {};

            function createErrorType(code, message, Base) {
                if (!Base) {
                    Base = Error;
                }

                function getMessage(arg1, arg2, arg3) {
                    if (typeof message === 'string') {
                        return message;
                    } else {
                        return message(arg1, arg2, arg3);
                    }
                }

                var NodeError =
                    /*#__PURE__*/
                    function (_Base) {
                        _inheritsLoose(NodeError, _Base);

                        function NodeError(arg1, arg2, arg3) {
                            return _Base.call(this, getMessage(arg1, arg2, arg3)) || this;
                        }

                        return NodeError;
                    }(Base);

                NodeError.prototype.name = Base.name;
                NodeError.prototype.code = code;
                codes[code] = NodeError;
            } // https://github.com/nodejs/node/blob/v10.8.0/lib/internal/errors.js


            function oneOf(expected, thing) {
                if (Array.isArray(expected)) {
                    var len = expected.length;
                    expected = expected.map(function (i) {
                        return String(i);
                    });

                    if (len > 2) {
                        return "one of ".concat(thing, " ").concat(expected.slice(0, len - 1).join(', '), ", or ") + expected[len - 1];
                    } else if (len === 2) {
                        return "one of ".concat(thing, " ").concat(expected[0], " or ").concat(expected[1]);
                    } else {
                        return "of ".concat(thing, " ").concat(expected[0]);
                    }
                } else {
                    return "of ".concat(thing, " ").concat(String(expected));
                }
            } // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith


            function startsWith(str, search, pos) {
                return str.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;
            } // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith


            function endsWith(str, search, this_len) {
                if (this_len === undefined || this_len > str.length) {
                    this_len = str.length;
                }

                return str.substring(this_len - search.length, this_len) === search;
            } // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes


            function includes(str, search, start) {
                if (typeof start !== 'number') {
                    start = 0;
                }

                if (start + search.length > str.length) {
                    return false;
                } else {
                    return str.indexOf(search, start) !== -1;
                }
            }

            createErrorType('ERR_INVALID_OPT_VALUE', function (name, value) {
                return 'The value "' + value + '" is invalid for option "' + name + '"';
            }, TypeError);
            createErrorType('ERR_INVALID_ARG_TYPE', function (name, expected, actual) {
                // determiner: 'must be' or 'must not be'
                var determiner;

                if (typeof expected === 'string' && startsWith(expected, 'not ')) {
                    determiner = 'must not be';
                    expected = expected.replace(/^not /, '');
                } else {
                    determiner = 'must be';
                }

                var msg;

                if (endsWith(name, ' argument')) {
                    // For cases like 'first argument'
                    msg = "The ".concat(name, " ").concat(determiner, " ").concat(oneOf(expected, 'type'));
                } else {
                    var type = includes(name, '.') ? 'property' : 'argument';
                    msg = "The \"".concat(name, "\" ").concat(type, " ").concat(determiner, " ").concat(oneOf(expected, 'type'));
                }

                msg += ". Received type ".concat(typeof actual);
                return msg;
            }, TypeError);
            createErrorType('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF');
            createErrorType('ERR_METHOD_NOT_IMPLEMENTED', function (name) {
                return 'The ' + name + ' method is not implemented';
            });
            createErrorType('ERR_STREAM_PREMATURE_CLOSE', 'Premature close');
            createErrorType('ERR_STREAM_DESTROYED', function (name) {
                return 'Cannot call ' + name + ' after a stream was destroyed';
            });
            createErrorType('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times');
            createErrorType('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable');
            createErrorType('ERR_STREAM_WRITE_AFTER_END', 'write after end');
            createErrorType('ERR_STREAM_NULL_VALUES', 'May not write null values to stream', TypeError);
            createErrorType('ERR_UNKNOWN_ENCODING', function (arg) {
                return 'Unknown encoding: ' + arg;
            }, TypeError);
            createErrorType('ERR_STREAM_UNSHIFT_AFTER_END_EVENT', 'stream.unshift() after end event');
            module.exports.codes = codes;

        }, {}], 11: [function (require, module, exports) {
            (function (process) {
                (function () {
                    // Copyright Joyent, Inc. and other Node contributors.
                    //
                    // Permission is hereby granted, free of charge, to any person obtaining a
                    // copy of this software and associated documentation files (the
                    // "Software"), to deal in the Software without restriction, including
                    // without limitation the rights to use, copy, modify, merge, publish,
                    // distribute, sublicense, and/or sell copies of the Software, and to permit
                    // persons to whom the Software is furnished to do so, subject to the
                    // following conditions:
                    //
                    // The above copyright notice and this permission notice shall be included
                    // in all copies or substantial portions of the Software.
                    //
                    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
                    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
                    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
                    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
                    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
                    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
                    // USE OR OTHER DEALINGS IN THE SOFTWARE.
                    // a duplex stream is just a stream that is both readable and writable.
                    // Since JS doesn't have multiple prototypal inheritance, this class
                    // prototypally inherits from Readable, and then parasitically from
                    // Writable.
                    'use strict';
                    /*<replacement>*/

                    var objectKeys = Object.keys || function (obj) {
                        var keys = [];

                        for (var key in obj) {
                            keys.push(key);
                        }

                        return keys;
                    };
                    /*</replacement>*/


                    module.exports = Duplex;

                    var Readable = require('./_stream_readable');

                    var Writable = require('./_stream_writable');

                    require('inherits')(Duplex, Readable);

                    {
                        // Allow the keys array to be GC'ed.
                        var keys = objectKeys(Writable.prototype);

                        for (var v = 0; v < keys.length; v++) {
                            var method = keys[v];
                            if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
                        }
                    }

                    function Duplex(options) {
                        if (!(this instanceof Duplex)) return new Duplex(options);
                        Readable.call(this, options);
                        Writable.call(this, options);
                        this.allowHalfOpen = true;

                        if (options) {
                            if (options.readable === false) this.readable = false;
                            if (options.writable === false) this.writable = false;

                            if (options.allowHalfOpen === false) {
                                this.allowHalfOpen = false;
                                this.once('end', onend);
                            }
                        }
                    }

                    Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', {
                        // making it explicit this property is not enumerable
                        // because otherwise some prototype manipulation in
                        // userland will fail
                        enumerable: false,
                        get: function get() {
                            return this._writableState.highWaterMark;
                        }
                    });
                    Object.defineProperty(Duplex.prototype, 'writableBuffer', {
                        // making it explicit this property is not enumerable
                        // because otherwise some prototype manipulation in
                        // userland will fail
                        enumerable: false,
                        get: function get() {
                            return this._writableState && this._writableState.getBuffer();
                        }
                    });
                    Object.defineProperty(Duplex.prototype, 'writableLength', {
                        // making it explicit this property is not enumerable
                        // because otherwise some prototype manipulation in
                        // userland will fail
                        enumerable: false,
                        get: function get() {
                            return this._writableState.length;
                        }
                    }); // the no-half-open enforcer

                    function onend() {
                        // If the writable side ended, then we're ok.
                        if (this._writableState.ended) return; // no more data can be written.
                        // But allow more writes to happen in this tick.

                        process.nextTick(onEndNT, this);
                    }

                    function onEndNT(self) {
                        self.end();
                    }

                    Object.defineProperty(Duplex.prototype, 'destroyed', {
                        // making it explicit this property is not enumerable
                        // because otherwise some prototype manipulation in
                        // userland will fail
                        enumerable: false,
                        get: function get() {
                            if (this._readableState === undefined || this._writableState === undefined) {
                                return false;
                            }

                            return this._readableState.destroyed && this._writableState.destroyed;
                        },
                        set: function set(value) {
                            // we ignore the value if the stream
                            // has not been initialized yet
                            if (this._readableState === undefined || this._writableState === undefined) {
                                return;
                            } // backward compatibility, the user is explicitly
                            // managing destroyed


                            this._readableState.destroyed = value;
                            this._writableState.destroyed = value;
                        }
                    });
                }).call(this)
            }).call(this, require('_process'))
        }, { "./_stream_readable": 13, "./_stream_writable": 15, "_process": 7, "inherits": 6 }], 12: [function (require, module, exports) {
            // Copyright Joyent, Inc. and other Node contributors.
            //
            // Permission is hereby granted, free of charge, to any person obtaining a
            // copy of this software and associated documentation files (the
            // "Software"), to deal in the Software without restriction, including
            // without limitation the rights to use, copy, modify, merge, publish,
            // distribute, sublicense, and/or sell copies of the Software, and to permit
            // persons to whom the Software is furnished to do so, subject to the
            // following conditions:
            //
            // The above copyright notice and this permission notice shall be included
            // in all copies or substantial portions of the Software.
            //
            // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
            // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
            // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
            // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
            // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
            // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
            // USE OR OTHER DEALINGS IN THE SOFTWARE.
            // a passthrough stream.
            // basically just the most minimal sort of Transform stream.
            // Every written chunk gets output as-is.
            'use strict';

            module.exports = PassThrough;

            var Transform = require('./_stream_transform');

            require('inherits')(PassThrough, Transform);

            function PassThrough(options) {
                if (!(this instanceof PassThrough)) return new PassThrough(options);
                Transform.call(this, options);
            }

            PassThrough.prototype._transform = function (chunk, encoding, cb) {
                cb(null, chunk);
            };
        }, { "./_stream_transform": 14, "inherits": 6 }], 13: [function (require, module, exports) {
            (function (process, global) {
                (function () {
                    // Copyright Joyent, Inc. and other Node contributors.
                    //
                    // Permission is hereby granted, free of charge, to any person obtaining a
                    // copy of this software and associated documentation files (the
                    // "Software"), to deal in the Software without restriction, including
                    // without limitation the rights to use, copy, modify, merge, publish,
                    // distribute, sublicense, and/or sell copies of the Software, and to permit
                    // persons to whom the Software is furnished to do so, subject to the
                    // following conditions:
                    //
                    // The above copyright notice and this permission notice shall be included
                    // in all copies or substantial portions of the Software.
                    //
                    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
                    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
                    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
                    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
                    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
                    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
                    // USE OR OTHER DEALINGS IN THE SOFTWARE.
                    'use strict';

                    module.exports = Readable;
                    /*<replacement>*/

                    var Duplex;
                    /*</replacement>*/

                    Readable.ReadableState = ReadableState;
                    /*<replacement>*/

                    var EE = require('events').EventEmitter;

                    var EElistenerCount = function EElistenerCount(emitter, type) {
                        return emitter.listeners(type).length;
                    };
                    /*</replacement>*/

                    /*<replacement>*/


                    var Stream = require('./internal/streams/stream');
                    /*</replacement>*/


                    var Buffer = require('buffer').Buffer;

                    var OurUint8Array = global.Uint8Array || function () { };

                    function _uint8ArrayToBuffer(chunk) {
                        return Buffer.from(chunk);
                    }

                    function _isUint8Array(obj) {
                        return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;
                    }
                    /*<replacement>*/


                    var debugUtil = require('util');

                    var debug;

                    if (debugUtil && debugUtil.debuglog) {
                        debug = debugUtil.debuglog('stream');
                    } else {
                        debug = function debug() { };
                    }
                    /*</replacement>*/


                    var BufferList = require('./internal/streams/buffer_list');

                    var destroyImpl = require('./internal/streams/destroy');

                    var _require = require('./internal/streams/state'),
                        getHighWaterMark = _require.getHighWaterMark;

                    var _require$codes = require('../errors').codes,
                        ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE,
                        ERR_STREAM_PUSH_AFTER_EOF = _require$codes.ERR_STREAM_PUSH_AFTER_EOF,
                        ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,
                        ERR_STREAM_UNSHIFT_AFTER_END_EVENT = _require$codes.ERR_STREAM_UNSHIFT_AFTER_END_EVENT; // Lazy loaded to improve the startup performance.


                    var StringDecoder;
                    var createReadableStreamAsyncIterator;
                    var from;

                    require('inherits')(Readable, Stream);

                    var errorOrDestroy = destroyImpl.errorOrDestroy;
                    var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume'];

                    function prependListener(emitter, event, fn) {
                        // Sadly this is not cacheable as some libraries bundle their own
                        // event emitter implementation with them.
                        if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn); // This is a hack to make sure that our error handler is attached before any
                        // userland ones.  NEVER DO THIS. This is here only because this code needs
                        // to continue to work with older versions of Node.js that do not include
                        // the prependListener() method. The goal is to eventually remove this hack.

                        if (!emitter._events || !emitter._events[event]) emitter.on(event, fn); else if (Array.isArray(emitter._events[event])) emitter._events[event].unshift(fn); else emitter._events[event] = [fn, emitter._events[event]];
                    }

                    function ReadableState(options, stream, isDuplex) {
                        Duplex = Duplex || require('./_stream_duplex');
                        options = options || {}; // Duplex streams are both readable and writable, but share
                        // the same options object.
                        // However, some cases require setting options to different
                        // values for the readable and the writable sides of the duplex stream.
                        // These options can be provided separately as readableXXX and writableXXX.

                        if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag. Used to make read(n) ignore n and to
                        // make all the buffer merging and length checks go away

                        this.objectMode = !!options.objectMode;
                        if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode; // the point at which it stops calling _read() to fill the buffer
                        // Note: 0 is a valid value, means "don't call _read preemptively ever"

                        this.highWaterMark = getHighWaterMark(this, options, 'readableHighWaterMark', isDuplex); // A linked list is used to store data chunks instead of an array because the
                        // linked list can remove elements from the beginning faster than
                        // array.shift()

                        this.buffer = new BufferList();
                        this.length = 0;
                        this.pipes = null;
                        this.pipesCount = 0;
                        this.flowing = null;
                        this.ended = false;
                        this.endEmitted = false;
                        this.reading = false; // a flag to be able to tell if the event 'readable'/'data' is emitted
                        // immediately, or on a later tick.  We set this to true at first, because
                        // any actions that shouldn't happen until "later" should generally also
                        // not happen before the first read call.

                        this.sync = true; // whenever we return null, then we set a flag to say
                        // that we're awaiting a 'readable' event emission.

                        this.needReadable = false;
                        this.emittedReadable = false;
                        this.readableListening = false;
                        this.resumeScheduled = false;
                        this.paused = true; // Should close be emitted on destroy. Defaults to true.

                        this.emitClose = options.emitClose !== false; // Should .destroy() be called after 'end' (and potentially 'finish')

                        this.autoDestroy = !!options.autoDestroy; // has it been destroyed

                        this.destroyed = false; // Crypto is kind of old and crusty.  Historically, its default string
                        // encoding is 'binary' so we have to make this configurable.
                        // Everything else in the universe uses 'utf8', though.

                        this.defaultEncoding = options.defaultEncoding || 'utf8'; // the number of writers that are awaiting a drain event in .pipe()s

                        this.awaitDrain = 0; // if true, a maybeReadMore has been scheduled

                        this.readingMore = false;
                        this.decoder = null;
                        this.encoding = null;

                        if (options.encoding) {
                            if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;
                            this.decoder = new StringDecoder(options.encoding);
                            this.encoding = options.encoding;
                        }
                    }

                    function Readable(options) {
                        Duplex = Duplex || require('./_stream_duplex');
                        if (!(this instanceof Readable)) return new Readable(options); // Checking for a Stream.Duplex instance is faster here instead of inside
                        // the ReadableState constructor, at least with V8 6.5

                        var isDuplex = this instanceof Duplex;
                        this._readableState = new ReadableState(options, this, isDuplex); // legacy

                        this.readable = true;

                        if (options) {
                            if (typeof options.read === 'function') this._read = options.read;
                            if (typeof options.destroy === 'function') this._destroy = options.destroy;
                        }

                        Stream.call(this);
                    }

                    Object.defineProperty(Readable.prototype, 'destroyed', {
                        // making it explicit this property is not enumerable
                        // because otherwise some prototype manipulation in
                        // userland will fail
                        enumerable: false,
                        get: function get() {
                            if (this._readableState === undefined) {
                                return false;
                            }

                            return this._readableState.destroyed;
                        },
                        set: function set(value) {
                            // we ignore the value if the stream
                            // has not been initialized yet
                            if (!this._readableState) {
                                return;
                            } // backward compatibility, the user is explicitly
                            // managing destroyed


                            this._readableState.destroyed = value;
                        }
                    });
                    Readable.prototype.destroy = destroyImpl.destroy;
                    Readable.prototype._undestroy = destroyImpl.undestroy;

                    Readable.prototype._destroy = function (err, cb) {
                        cb(err);
                    }; // Manually shove something into the read() buffer.
                    // This returns true if the highWaterMark has not been hit yet,
                    // similar to how Writable.write() returns true if you should
                    // write() some more.


                    Readable.prototype.push = function (chunk, encoding) {
                        var state = this._readableState;
                        var skipChunkCheck;

                        if (!state.objectMode) {
                            if (typeof chunk === 'string') {
                                encoding = encoding || state.defaultEncoding;

                                if (encoding !== state.encoding) {
                                    chunk = Buffer.from(chunk, encoding);
                                    encoding = '';
                                }

                                skipChunkCheck = true;
                            }
                        } else {
                            skipChunkCheck = true;
                        }

                        return readableAddChunk(this, chunk, encoding, false, skipChunkCheck);
                    }; // Unshift should *always* be something directly out of read()


                    Readable.prototype.unshift = function (chunk) {
                        return readableAddChunk(this, chunk, null, true, false);
                    };

                    function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) {
                        debug('readableAddChunk', chunk);
                        var state = stream._readableState;

                        if (chunk === null) {
                            state.reading = false;
                            onEofChunk(stream, state);
                        } else {
                            var er;
                            if (!skipChunkCheck) er = chunkInvalid(state, chunk);

                            if (er) {
                                errorOrDestroy(stream, er);
                            } else if (state.objectMode || chunk && chunk.length > 0) {
                                if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) {
                                    chunk = _uint8ArrayToBuffer(chunk);
                                }

                                if (addToFront) {
                                    if (state.endEmitted) errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT()); else addChunk(stream, state, chunk, true);
                                } else if (state.ended) {
                                    errorOrDestroy(stream, new ERR_STREAM_PUSH_AFTER_EOF());
                                } else if (state.destroyed) {
                                    return false;
                                } else {
                                    state.reading = false;

                                    if (state.decoder && !encoding) {
                                        chunk = state.decoder.write(chunk);
                                        if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false); else maybeReadMore(stream, state);
                                    } else {
                                        addChunk(stream, state, chunk, false);
                                    }
                                }
                            } else if (!addToFront) {
                                state.reading = false;
                                maybeReadMore(stream, state);
                            }
                        } // We can push more data if we are below the highWaterMark.
                        // Also, if we have no data yet, we can stand some more bytes.
                        // This is to work around cases where hwm=0, such as the repl.


                        return !state.ended && (state.length < state.highWaterMark || state.length === 0);
                    }

                    function addChunk(stream, state, chunk, addToFront) {
                        if (state.flowing && state.length === 0 && !state.sync) {
                            state.awaitDrain = 0;
                            stream.emit('data', chunk);
                        } else {
                            // update the buffer info.
                            state.length += state.objectMode ? 1 : chunk.length;
                            if (addToFront) state.buffer.unshift(chunk); else state.buffer.push(chunk);
                            if (state.needReadable) emitReadable(stream);
                        }

                        maybeReadMore(stream, state);
                    }

                    function chunkInvalid(state, chunk) {
                        var er;

                        if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {
                            er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer', 'Uint8Array'], chunk);
                        }

                        return er;
                    }

                    Readable.prototype.isPaused = function () {
                        return this._readableState.flowing === false;
                    }; // backwards compatibility.


                    Readable.prototype.setEncoding = function (enc) {
                        if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;
                        var decoder = new StringDecoder(enc);
                        this._readableState.decoder = decoder; // If setEncoding(null), decoder.encoding equals utf8

                        this._readableState.encoding = this._readableState.decoder.encoding; // Iterate over current buffer to convert already stored Buffers:

                        var p = this._readableState.buffer.head;
                        var content = '';

                        while (p !== null) {
                            content += decoder.write(p.data);
                            p = p.next;
                        }

                        this._readableState.buffer.clear();

                        if (content !== '') this._readableState.buffer.push(content);
                        this._readableState.length = content.length;
                        return this;
                    }; // Don't raise the hwm > 1GB


                    var MAX_HWM = 0x40000000;

                    function computeNewHighWaterMark(n) {
                        if (n >= MAX_HWM) {
                            // TODO(ronag): Throw ERR_VALUE_OUT_OF_RANGE.
                            n = MAX_HWM;
                        } else {
                            // Get the next highest power of 2 to prevent increasing hwm excessively in
                            // tiny amounts
                            n--;
                            n |= n >>> 1;
                            n |= n >>> 2;
                            n |= n >>> 4;
                            n |= n >>> 8;
                            n |= n >>> 16;
                            n++;
                        }

                        return n;
                    } // This function is designed to be inlinable, so please take care when making
                    // changes to the function body.


                    function howMuchToRead(n, state) {
                        if (n <= 0 || state.length === 0 && state.ended) return 0;
                        if (state.objectMode) return 1;

                        if (n !== n) {
                            // Only flow one buffer at a time
                            if (state.flowing && state.length) return state.buffer.head.data.length; else return state.length;
                        } // If we're asking for more than the current hwm, then raise the hwm.


                        if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n);
                        if (n <= state.length) return n; // Don't have enough

                        if (!state.ended) {
                            state.needReadable = true;
                            return 0;
                        }

                        return state.length;
                    } // you can override either this method, or the async _read(n) below.


                    Readable.prototype.read = function (n) {
                        debug('read', n);
                        n = parseInt(n, 10);
                        var state = this._readableState;
                        var nOrig = n;
                        if (n !== 0) state.emittedReadable = false; // if we're doing read(0) to trigger a readable event, but we
                        // already have a bunch of data in the buffer, then just trigger
                        // the 'readable' event and move on.

                        if (n === 0 && state.needReadable && ((state.highWaterMark !== 0 ? state.length >= state.highWaterMark : state.length > 0) || state.ended)) {
                            debug('read: emitReadable', state.length, state.ended);
                            if (state.length === 0 && state.ended) endReadable(this); else emitReadable(this);
                            return null;
                        }

                        n = howMuchToRead(n, state); // if we've ended, and we're now clear, then finish it up.

                        if (n === 0 && state.ended) {
                            if (state.length === 0) endReadable(this);
                            return null;
                        } // All the actual chunk generation logic needs to be
                        // *below* the call to _read.  The reason is that in certain
                        // synthetic stream cases, such as passthrough streams, _read
                        // may be a completely synchronous operation which may change
                        // the state of the read buffer, providing enough data when
                        // before there was *not* enough.
                        //
                        // So, the steps are:
                        // 1. Figure out what the state of things will be after we do
                        // a read from the buffer.
                        //
                        // 2. If that resulting state will trigger a _read, then call _read.
                        // Note that this may be asynchronous, or synchronous.  Yes, it is
                        // deeply ugly to write APIs this way, but that still doesn't mean
                        // that the Readable class should behave improperly, as streams are
                        // designed to be sync/async agnostic.
                        // Take note if the _read call is sync or async (ie, if the read call
                        // has returned yet), so that we know whether or not it's safe to emit
                        // 'readable' etc.
                        //
                        // 3. Actually pull the requested chunks out of the buffer and return.
                        // if we need a readable event, then we need to do some reading.


                        var doRead = state.needReadable;
                        debug('need readable', doRead); // if we currently have less than the highWaterMark, then also read some

                        if (state.length === 0 || state.length - n < state.highWaterMark) {
                            doRead = true;
                            debug('length less than watermark', doRead);
                        } // however, if we've ended, then there's no point, and if we're already
                        // reading, then it's unnecessary.


                        if (state.ended || state.reading) {
                            doRead = false;
                            debug('reading or ended', doRead);
                        } else if (doRead) {
                            debug('do read');
                            state.reading = true;
                            state.sync = true; // if the length is currently zero, then we *need* a readable event.

                            if (state.length === 0) state.needReadable = true; // call internal read method

                            this._read(state.highWaterMark);

                            state.sync = false; // If _read pushed data synchronously, then `reading` will be false,
                            // and we need to re-evaluate how much data we can return to the user.

                            if (!state.reading) n = howMuchToRead(nOrig, state);
                        }

                        var ret;
                        if (n > 0) ret = fromList(n, state); else ret = null;

                        if (ret === null) {
                            state.needReadable = state.length <= state.highWaterMark;
                            n = 0;
                        } else {
                            state.length -= n;
                            state.awaitDrain = 0;
                        }

                        if (state.length === 0) {
                            // If we have nothing in the buffer, then we want to know
                            // as soon as we *do* get something into the buffer.
                            if (!state.ended) state.needReadable = true; // If we tried to read() past the EOF, then emit end on the next tick.

                            if (nOrig !== n && state.ended) endReadable(this);
                        }

                        if (ret !== null) this.emit('data', ret);
                        return ret;
                    };

                    function onEofChunk(stream, state) {
                        debug('onEofChunk');
                        if (state.ended) return;

                        if (state.decoder) {
                            var chunk = state.decoder.end();

                            if (chunk && chunk.length) {
                                state.buffer.push(chunk);
                                state.length += state.objectMode ? 1 : chunk.length;
                            }
                        }

                        state.ended = true;

                        if (state.sync) {
                            // if we are sync, wait until next tick to emit the data.
                            // Otherwise we risk emitting data in the flow()
                            // the readable code triggers during a read() call
                            emitReadable(stream);
                        } else {
                            // emit 'readable' now to make sure it gets picked up.
                            state.needReadable = false;

                            if (!state.emittedReadable) {
                                state.emittedReadable = true;
                                emitReadable_(stream);
                            }
                        }
                    } // Don't emit readable right away in sync mode, because this can trigger
                    // another read() call => stack overflow.  This way, it might trigger
                    // a nextTick recursion warning, but that's not so bad.


                    function emitReadable(stream) {
                        var state = stream._readableState;
                        debug('emitReadable', state.needReadable, state.emittedReadable);
                        state.needReadable = false;

                        if (!state.emittedReadable) {
                            debug('emitReadable', state.flowing);
                            state.emittedReadable = true;
                            process.nextTick(emitReadable_, stream);
                        }
                    }

                    function emitReadable_(stream) {
                        var state = stream._readableState;
                        debug('emitReadable_', state.destroyed, state.length, state.ended);

                        if (!state.destroyed && (state.length || state.ended)) {
                            stream.emit('readable');
                            state.emittedReadable = false;
                        } // The stream needs another readable event if
                        // 1. It is not flowing, as the flow mechanism will take
                        //    care of it.
                        // 2. It is not ended.
                        // 3. It is below the highWaterMark, so we can schedule
                        //    another readable later.


                        state.needReadable = !state.flowing && !state.ended && state.length <= state.highWaterMark;
                        flow(stream);
                    } // at this point, the user has presumably seen the 'readable' event,
                    // and called read() to consume some data.  that may have triggered
                    // in turn another _read(n) call, in which case reading = true if
                    // it's in progress.
                    // However, if we're not ended, or reading, and the length < hwm,
                    // then go ahead and try to read some more preemptively.


                    function maybeReadMore(stream, state) {
                        if (!state.readingMore) {
                            state.readingMore = true;
                            process.nextTick(maybeReadMore_, stream, state);
                        }
                    }

                    function maybeReadMore_(stream, state) {
                        // Attempt to read more data if we should.
                        //
                        // The conditions for reading more data are (one of):
                        // - Not enough data buffered (state.length < state.highWaterMark). The loop
                        //   is responsible for filling the buffer with enough data if such data
                        //   is available. If highWaterMark is 0 and we are not in the flowing mode
                        //   we should _not_ attempt to buffer any extra data. We'll get more data
                        //   when the stream consumer calls read() instead.
                        // - No data in the buffer, and the stream is in flowing mode. In this mode
                        //   the loop below is responsible for ensuring read() is called. Failing to
                        //   call read here would abort the flow and there's no other mechanism for
                        //   continuing the flow if the stream consumer has just subscribed to the
                        //   'data' event.
                        //
                        // In addition to the above conditions to keep reading data, the following
                        // conditions prevent the data from being read:
                        // - The stream has ended (state.ended).
                        // - There is already a pending 'read' operation (state.reading). This is a
                        //   case where the the stream has called the implementation defined _read()
                        //   method, but they are processing the call asynchronously and have _not_
                        //   called push() with new data. In this case we skip performing more
                        //   read()s. The execution ends in this method again after the _read() ends
                        //   up calling push() with more data.
                        while (!state.reading && !state.ended && (state.length < state.highWaterMark || state.flowing && state.length === 0)) {
                            var len = state.length;
                            debug('maybeReadMore read 0');
                            stream.read(0);
                            if (len === state.length) // didn't get any data, stop spinning.
                                break;
                        }

                        state.readingMore = false;
                    } // abstract method.  to be overridden in specific implementation classes.
                    // call cb(er, data) where data is <= n in length.
                    // for virtual (non-string, non-buffer) streams, "length" is somewhat
                    // arbitrary, and perhaps not very meaningful.


                    Readable.prototype._read = function (n) {
                        errorOrDestroy(this, new ERR_METHOD_NOT_IMPLEMENTED('_read()'));
                    };

                    Readable.prototype.pipe = function (dest, pipeOpts) {
                        var src = this;
                        var state = this._readableState;

                        switch (state.pipesCount) {
                            case 0:
                                state.pipes = dest;
                                break;

                            case 1:
                                state.pipes = [state.pipes, dest];
                                break;

                            default:
                                state.pipes.push(dest);
                                break;
                        }

                        state.pipesCount += 1;
                        debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts);
                        var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr;
                        var endFn = doEnd ? onend : unpipe;
                        if (state.endEmitted) process.nextTick(endFn); else src.once('end', endFn);
                        dest.on('unpipe', onunpipe);

                        function onunpipe(readable, unpipeInfo) {
                            debug('onunpipe');

                            if (readable === src) {
                                if (unpipeInfo && unpipeInfo.hasUnpiped === false) {
                                    unpipeInfo.hasUnpiped = true;
                                    cleanup();
                                }
                            }
                        }

                        function onend() {
                            debug('onend');
                            dest.end();
                        } // when the dest drains, it reduces the awaitDrain counter
                        // on the source.  This would be more elegant with a .once()
                        // handler in flow(), but adding and removing repeatedly is
                        // too slow.


                        var ondrain = pipeOnDrain(src);
                        dest.on('drain', ondrain);
                        var cleanedUp = false;

                        function cleanup() {
                            debug('cleanup'); // cleanup event handlers once the pipe is broken

                            dest.removeListener('close', onclose);
                            dest.removeListener('finish', onfinish);
                            dest.removeListener('drain', ondrain);
                            dest.removeListener('error', onerror);
                            dest.removeListener('unpipe', onunpipe);
                            src.removeListener('end', onend);
                            src.removeListener('end', unpipe);
                            src.removeListener('data', ondata);
                            cleanedUp = true; // if the reader is waiting for a drain event from this
                            // specific writer, then it would cause it to never start
                            // flowing again.
                            // So, if this is awaiting a drain, then we just call it now.
                            // If we don't know, then assume that we are waiting for one.

                            if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain();
                        }

                        src.on('data', ondata);

                        function ondata(chunk) {
                            debug('ondata');
                            var ret = dest.write(chunk);
                            debug('dest.write', ret);

                            if (ret === false) {
                                // If the user unpiped during `dest.write()`, it is possible
                                // to get stuck in a permanently paused state if that write
                                // also returned false.
                                // => Check whether `dest` is still a piping destination.
                                if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) {
                                    debug('false write response, pause', state.awaitDrain);
                                    state.awaitDrain++;
                                }

                                src.pause();
                            }
                        } // if the dest has an error, then stop piping into it.
                        // however, don't suppress the throwing behavior for this.


                        function onerror(er) {
                            debug('onerror', er);
                            unpipe();
                            dest.removeListener('error', onerror);
                            if (EElistenerCount(dest, 'error') === 0) errorOrDestroy(dest, er);
                        } // Make sure our error handler is attached before userland ones.


                        prependListener(dest, 'error', onerror); // Both close and finish should trigger unpipe, but only once.

                        function onclose() {
                            dest.removeListener('finish', onfinish);
                            unpipe();
                        }

                        dest.once('close', onclose);

                        function onfinish() {
                            debug('onfinish');
                            dest.removeListener('close', onclose);
                            unpipe();
                        }

                        dest.once('finish', onfinish);

                        function unpipe() {
                            debug('unpipe');
                            src.unpipe(dest);
                        } // tell the dest that it's being piped to


                        dest.emit('pipe', src); // start the flow if it hasn't been started already.

                        if (!state.flowing) {
                            debug('pipe resume');
                            src.resume();
                        }

                        return dest;
                    };

                    function pipeOnDrain(src) {
                        return function pipeOnDrainFunctionResult() {
                            var state = src._readableState;
                            debug('pipeOnDrain', state.awaitDrain);
                            if (state.awaitDrain) state.awaitDrain--;

                            if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) {
                                state.flowing = true;
                                flow(src);
                            }
                        };
                    }

                    Readable.prototype.unpipe = function (dest) {
                        var state = this._readableState;
                        var unpipeInfo = {
                            hasUnpiped: false
                        }; // if we're not piping anywhere, then do nothing.

                        if (state.pipesCount === 0) return this; // just one destination.  most common case.

                        if (state.pipesCount === 1) {
                            // passed in one, but it's not the right one.
                            if (dest && dest !== state.pipes) return this;
                            if (!dest) dest = state.pipes; // got a match.

                            state.pipes = null;
                            state.pipesCount = 0;
                            state.flowing = false;
                            if (dest) dest.emit('unpipe', this, unpipeInfo);
                            return this;
                        } // slow case. multiple pipe destinations.


                        if (!dest) {
                            // remove all.
                            var dests = state.pipes;
                            var len = state.pipesCount;
                            state.pipes = null;
                            state.pipesCount = 0;
                            state.flowing = false;

                            for (var i = 0; i < len; i++) {
                                dests[i].emit('unpipe', this, {
                                    hasUnpiped: false
                                });
                            }

                            return this;
                        } // try to find the right one.


                        var index = indexOf(state.pipes, dest);
                        if (index === -1) return this;
                        state.pipes.splice(index, 1);
                        state.pipesCount -= 1;
                        if (state.pipesCount === 1) state.pipes = state.pipes[0];
                        dest.emit('unpipe', this, unpipeInfo);
                        return this;
                    }; // set up data events if they are asked for
                    // Ensure readable listeners eventually get something


                    Readable.prototype.on = function (ev, fn) {
                        var res = Stream.prototype.on.call(this, ev, fn);
                        var state = this._readableState;

                        if (ev === 'data') {
                            // update readableListening so that resume() may be a no-op
                            // a few lines down. This is needed to support once('readable').
                            state.readableListening = this.listenerCount('readable') > 0; // Try start flowing on next tick if stream isn't explicitly paused

                            if (state.flowing !== false) this.resume();
                        } else if (ev === 'readable') {
                            if (!state.endEmitted && !state.readableListening) {
                                state.readableListening = state.needReadable = true;
                                state.flowing = false;
                                state.emittedReadable = false;
                                debug('on readable', state.length, state.reading);

                                if (state.length) {
                                    emitReadable(this);
                                } else if (!state.reading) {
                                    process.nextTick(nReadingNextTick, this);
                                }
                            }
                        }

                        return res;
                    };

                    Readable.prototype.addListener = Readable.prototype.on;

                    Readable.prototype.removeListener = function (ev, fn) {
                        var res = Stream.prototype.removeListener.call(this, ev, fn);

                        if (ev === 'readable') {
                            // We need to check if there is someone still listening to
                            // readable and reset the state. However this needs to happen
                            // after readable has been emitted but before I/O (nextTick) to
                            // support once('readable', fn) cycles. This means that calling
                            // resume within the same tick will have no
                            // effect.
                            process.nextTick(updateReadableListening, this);
                        }

                        return res;
                    };

                    Readable.prototype.removeAllListeners = function (ev) {
                        var res = Stream.prototype.removeAllListeners.apply(this, arguments);

                        if (ev === 'readable' || ev === undefined) {
                            // We need to check if there is someone still listening to
                            // readable and reset the state. However this needs to happen
                            // after readable has been emitted but before I/O (nextTick) to
                            // support once('readable', fn) cycles. This means that calling
                            // resume within the same tick will have no
                            // effect.
                            process.nextTick(updateReadableListening, this);
                        }

                        return res;
                    };

                    function updateReadableListening(self) {
                        var state = self._readableState;
                        state.readableListening = self.listenerCount('readable') > 0;

                        if (state.resumeScheduled && !state.paused) {
                            // flowing needs to be set to true now, otherwise
                            // the upcoming resume will not flow.
                            state.flowing = true; // crude way to check if we should resume
                        } else if (self.listenerCount('data') > 0) {
                            self.resume();
                        }
                    }

                    function nReadingNextTick(self) {
                        debug('readable nexttick read 0');
                        self.read(0);
                    } // pause() and resume() are remnants of the legacy readable stream API
                    // If the user uses them, then switch into old mode.


                    Readable.prototype.resume = function () {
                        var state = this._readableState;

                        if (!state.flowing) {
                            debug('resume'); // we flow only if there is no one listening
                            // for readable, but we still have to call
                            // resume()

                            state.flowing = !state.readableListening;
                            resume(this, state);
                        }

                        state.paused = false;
                        return this;
                    };

                    function resume(stream, state) {
                        if (!state.resumeScheduled) {
                            state.resumeScheduled = true;
                            process.nextTick(resume_, stream, state);
                        }
                    }

                    function resume_(stream, state) {
                        debug('resume', state.reading);

                        if (!state.reading) {
                            stream.read(0);
                        }

                        state.resumeScheduled = false;
                        stream.emit('resume');
                        flow(stream);
                        if (state.flowing && !state.reading) stream.read(0);
                    }

                    Readable.prototype.pause = function () {
                        debug('call pause flowing=%j', this._readableState.flowing);

                        if (this._readableState.flowing !== false) {
                            debug('pause');
                            this._readableState.flowing = false;
                            this.emit('pause');
                        }

                        this._readableState.paused = true;
                        return this;
                    };

                    function flow(stream) {
                        var state = stream._readableState;
                        debug('flow', state.flowing);

                        while (state.flowing && stream.read() !== null) {
                            ;
                        }
                    } // wrap an old-style stream as the async data source.
                    // This is *not* part of the readable stream interface.
                    // It is an ugly unfortunate mess of history.


                    Readable.prototype.wrap = function (stream) {
                        var _this = this;

                        var state = this._readableState;
                        var paused = false;
                        stream.on('end', function () {
                            debug('wrapped end');

                            if (state.decoder && !state.ended) {
                                var chunk = state.decoder.end();
                                if (chunk && chunk.length) _this.push(chunk);
                            }

                            _this.push(null);
                        });
                        stream.on('data', function (chunk) {
                            debug('wrapped data');
                            if (state.decoder) chunk = state.decoder.write(chunk); // don't skip over falsy values in objectMode

                            if (state.objectMode && (chunk === null || chunk === undefined)) return; else if (!state.objectMode && (!chunk || !chunk.length)) return;

                            var ret = _this.push(chunk);

                            if (!ret) {
                                paused = true;
                                stream.pause();
                            }
                        }); // proxy all the other methods.
                        // important when wrapping filters and duplexes.

                        for (var i in stream) {
                            if (this[i] === undefined && typeof stream[i] === 'function') {
                                this[i] = function methodWrap(method) {
                                    return function methodWrapReturnFunction() {
                                        return stream[method].apply(stream, arguments);
                                    };
                                }(i);
                            }
                        } // proxy certain important events.


                        for (var n = 0; n < kProxyEvents.length; n++) {
                            stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n]));
                        } // when we try to consume some more bytes, simply unpause the
                        // underlying stream.


                        this._read = function (n) {
                            debug('wrapped _read', n);

                            if (paused) {
                                paused = false;
                                stream.resume();
                            }
                        };

                        return this;
                    };

                    if (typeof Symbol === 'function') {
                        Readable.prototype[Symbol.asyncIterator] = function () {
                            if (createReadableStreamAsyncIterator === undefined) {
                                createReadableStreamAsyncIterator = require('./internal/streams/async_iterator');
                            }

                            return createReadableStreamAsyncIterator(this);
                        };
                    }

                    Object.defineProperty(Readable.prototype, 'readableHighWaterMark', {
                        // making it explicit this property is not enumerable
                        // because otherwise some prototype manipulation in
                        // userland will fail
                        enumerable: false,
                        get: function get() {
                            return this._readableState.highWaterMark;
                        }
                    });
                    Object.defineProperty(Readable.prototype, 'readableBuffer', {
                        // making it explicit this property is not enumerable
                        // because otherwise some prototype manipulation in
                        // userland will fail
                        enumerable: false,
                        get: function get() {
                            return this._readableState && this._readableState.buffer;
                        }
                    });
                    Object.defineProperty(Readable.prototype, 'readableFlowing', {
                        // making it explicit this property is not enumerable
                        // because otherwise some prototype manipulation in
                        // userland will fail
                        enumerable: false,
                        get: function get() {
                            return this._readableState.flowing;
                        },
                        set: function set(state) {
                            if (this._readableState) {
                                this._readableState.flowing = state;
                            }
                        }
                    }); // exposed for testing purposes only.

                    Readable._fromList = fromList;
                    Object.defineProperty(Readable.prototype, 'readableLength', {
                        // making it explicit this property is not enumerable
                        // because otherwise some prototype manipulation in
                        // userland will fail
                        enumerable: false,
                        get: function get() {
                            return this._readableState.length;
                        }
                    }); // Pluck off n bytes from an array of buffers.
                    // Length is the combined lengths of all the buffers in the list.
                    // This function is designed to be inlinable, so please take care when making
                    // changes to the function body.

                    function fromList(n, state) {
                        // nothing buffered
                        if (state.length === 0) return null;
                        var ret;
                        if (state.objectMode) ret = state.buffer.shift(); else if (!n || n >= state.length) {
                            // read it all, truncate the list
                            if (state.decoder) ret = state.buffer.join(''); else if (state.buffer.length === 1) ret = state.buffer.first(); else ret = state.buffer.concat(state.length);
                            state.buffer.clear();
                        } else {
                            // read part of list
                            ret = state.buffer.consume(n, state.decoder);
                        }
                        return ret;
                    }

                    function endReadable(stream) {
                        var state = stream._readableState;
                        debug('endReadable', state.endEmitted);

                        if (!state.endEmitted) {
                            state.ended = true;
                            process.nextTick(endReadableNT, state, stream);
                        }
                    }

                    function endReadableNT(state, stream) {
                        debug('endReadableNT', state.endEmitted, state.length); // Check that we didn't get one last unshift.

                        if (!state.endEmitted && state.length === 0) {
                            state.endEmitted = true;
                            stream.readable = false;
                            stream.emit('end');

                            if (state.autoDestroy) {
                                // In case of duplex streams we need a way to detect
                                // if the writable side is ready for autoDestroy as well
                                var wState = stream._writableState;

                                if (!wState || wState.autoDestroy && wState.finished) {
                                    stream.destroy();
                                }
                            }
                        }
                    }

                    if (typeof Symbol === 'function') {
                        Readable.from = function (iterable, opts) {
                            if (from === undefined) {
                                from = require('./internal/streams/from');
                            }

                            return from(Readable, iterable, opts);
                        };
                    }

                    function indexOf(xs, x) {
                        for (var i = 0, l = xs.length; i < l; i++) {
                            if (xs[i] === x) return i;
                        }

                        return -1;
                    }
                }).call(this)
            }).call(this, require('_process'), typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
        }, { "../errors": 10, "./_stream_duplex": 11, "./internal/streams/async_iterator": 16, "./internal/streams/buffer_list": 17, "./internal/streams/destroy": 18, "./internal/streams/from": 20, "./internal/streams/state": 22, "./internal/streams/stream": 23, "_process": 7, "buffer": 3, "events": 4, "inherits": 6, "string_decoder/": 24, "util": 2 }], 14: [function (require, module, exports) {
            // Copyright Joyent, Inc. and other Node contributors.
            //
            // Permission is hereby granted, free of charge, to any person obtaining a
            // copy of this software and associated documentation files (the
            // "Software"), to deal in the Software without restriction, including
            // without limitation the rights to use, copy, modify, merge, publish,
            // distribute, sublicense, and/or sell copies of the Software, and to permit
            // persons to whom the Software is furnished to do so, subject to the
            // following conditions:
            //
            // The above copyright notice and this permission notice shall be included
            // in all copies or substantial portions of the Software.
            //
            // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
            // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
            // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
            // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
            // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
            // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
            // USE OR OTHER DEALINGS IN THE SOFTWARE.
            // a transform stream is a readable/writable stream where you do
            // something with the data.  Sometimes it's called a "filter",
            // but that's not a great name for it, since that implies a thing where
            // some bits pass through, and others are simply ignored.  (That would
            // be a valid example of a transform, of course.)
            //
            // While the output is causally related to the input, it's not a
            // necessarily symmetric or synchronous transformation.  For example,
            // a zlib stream might take multiple plain-text writes(), and then
            // emit a single compressed chunk some time in the future.
            //
            // Here's how this works:
            //
            // The Transform stream has all the aspects of the readable and writable
            // stream classes.  When you write(chunk), that calls _write(chunk,cb)
            // internally, and returns false if there's a lot of pending writes
            // buffered up.  When you call read(), that calls _read(n) until
            // there's enough pending readable data buffered up.
            //
            // In a transform stream, the written data is placed in a buffer.  When
            // _read(n) is called, it transforms the queued up data, calling the
            // buffered _write cb's as it consumes chunks.  If consuming a single
            // written chunk would result in multiple output chunks, then the first
            // outputted bit calls the readcb, and subsequent chunks just go into
            // the read buffer, and will cause it to emit 'readable' if necessary.
            //
            // This way, back-pressure is actually determined by the reading side,
            // since _read has to be called to start processing a new chunk.  However,
            // a pathological inflate type of transform can cause excessive buffering
            // here.  For example, imagine a stream where every byte of input is
            // interpreted as an integer from 0-255, and then results in that many
            // bytes of output.  Writing the 4 bytes {ff,ff,ff,ff} would result in
            // 1kb of data being output.  In this case, you could write a very small
            // amount of input, and end up with a very large amount of output.  In
            // such a pathological inflating mechanism, there'd be no way to tell
            // the system to stop doing the transform.  A single 4MB write could
            // cause the system to run out of memory.
            //
            // However, even in such a pathological case, only a single written chunk
            // would be consumed, and then the rest would wait (un-transformed) until
            // the results of the previous transformed chunk were consumed.
            'use strict';

            module.exports = Transform;

            var _require$codes = require('../errors').codes,
                ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,
                ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK,
                ERR_TRANSFORM_ALREADY_TRANSFORMING = _require$codes.ERR_TRANSFORM_ALREADY_TRANSFORMING,
                ERR_TRANSFORM_WITH_LENGTH_0 = _require$codes.ERR_TRANSFORM_WITH_LENGTH_0;

            var Duplex = require('./_stream_duplex');

            require('inherits')(Transform, Duplex);

            function afterTransform(er, data) {
                var ts = this._transformState;
                ts.transforming = false;
                var cb = ts.writecb;

                if (cb === null) {
                    return this.emit('error', new ERR_MULTIPLE_CALLBACK());
                }

                ts.writechunk = null;
                ts.writecb = null;
                if (data != null) // single equals check for both `null` and `undefined`
                    this.push(data);
                cb(er);
                var rs = this._readableState;
                rs.reading = false;

                if (rs.needReadable || rs.length < rs.highWaterMark) {
                    this._read(rs.highWaterMark);
                }
            }

            function Transform(options) {
                if (!(this instanceof Transform)) return new Transform(options);
                Duplex.call(this, options);
                this._transformState = {
                    afterTransform: afterTransform.bind(this),
                    needTransform: false,
                    transforming: false,
                    writecb: null,
                    writechunk: null,
                    writeencoding: null
                }; // start out asking for a readable event once data is transformed.

                this._readableState.needReadable = true; // we have implemented the _read method, and done the other things
                // that Readable wants before the first _read call, so unset the
                // sync guard flag.

                this._readableState.sync = false;

                if (options) {
                    if (typeof options.transform === 'function') this._transform = options.transform;
                    if (typeof options.flush === 'function') this._flush = options.flush;
                } // When the writable side finishes, then flush out anything remaining.


                this.on('prefinish', prefinish);
            }

            function prefinish() {
                var _this = this;

                if (typeof this._flush === 'function' && !this._readableState.destroyed) {
                    this._flush(function (er, data) {
                        done(_this, er, data);
                    });
                } else {
                    done(this, null, null);
                }
            }

            Transform.prototype.push = function (chunk, encoding) {
                this._transformState.needTransform = false;
                return Duplex.prototype.push.call(this, chunk, encoding);
            }; // This is the part where you do stuff!
            // override this function in implementation classes.
            // 'chunk' is an input chunk.
            //
            // Call `push(newChunk)` to pass along transformed output
            // to the readable side.  You may call 'push' zero or more times.
            //
            // Call `cb(err)` when you are done with this chunk.  If you pass
            // an error, then that'll put the hurt on the whole operation.  If you
            // never call cb(), then you'll never get another chunk.


            Transform.prototype._transform = function (chunk, encoding, cb) {
                cb(new ERR_METHOD_NOT_IMPLEMENTED('_transform()'));
            };

            Transform.prototype._write = function (chunk, encoding, cb) {
                var ts = this._transformState;
                ts.writecb = cb;
                ts.writechunk = chunk;
                ts.writeencoding = encoding;

                if (!ts.transforming) {
                    var rs = this._readableState;
                    if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark);
                }
            }; // Doesn't matter what the args are here.
            // _transform does all the work.
            // That we got here means that the readable side wants more data.


            Transform.prototype._read = function (n) {
                var ts = this._transformState;

                if (ts.writechunk !== null && !ts.transforming) {
                    ts.transforming = true;

                    this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);
                } else {
                    // mark that we need a transform, so that any data that comes in
                    // will get processed, now that we've asked for it.
                    ts.needTransform = true;
                }
            };

            Transform.prototype._destroy = function (err, cb) {
                Duplex.prototype._destroy.call(this, err, function (err2) {
                    cb(err2);
                });
            };

            function done(stream, er, data) {
                if (er) return stream.emit('error', er);
                if (data != null) // single equals check for both `null` and `undefined`
                    stream.push(data); // TODO(BridgeAR): Write a test for these two error cases
                // if there's nothing in the write buffer, then that means
                // that nothing more will ever be provided

                if (stream._writableState.length) throw new ERR_TRANSFORM_WITH_LENGTH_0();
                if (stream._transformState.transforming) throw new ERR_TRANSFORM_ALREADY_TRANSFORMING();
                return stream.push(null);
            }
        }, { "../errors": 10, "./_stream_duplex": 11, "inherits": 6 }], 15: [function (require, module, exports) {
            (function (process, global) {
                (function () {
                    // Copyright Joyent, Inc. and other Node contributors.
                    //
                    // Permission is hereby granted, free of charge, to any person obtaining a
                    // copy of this software and associated documentation files (the
                    // "Software"), to deal in the Software without restriction, including
                    // without limitation the rights to use, copy, modify, merge, publish,
                    // distribute, sublicense, and/or sell copies of the Software, and to permit
                    // persons to whom the Software is furnished to do so, subject to the
                    // following conditions:
                    //
                    // The above copyright notice and this permission notice shall be included
                    // in all copies or substantial portions of the Software.
                    //
                    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
                    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
                    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
                    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
                    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
                    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
                    // USE OR OTHER DEALINGS IN THE SOFTWARE.
                    // A bit simpler than readable streams.
                    // Implement an async ._write(chunk, encoding, cb), and it'll handle all
                    // the drain event emission and buffering.
                    'use strict';

                    module.exports = Writable;
                    /* <replacement> */

                    function WriteReq(chunk, encoding, cb) {
                        this.chunk = chunk;
                        this.encoding = encoding;
                        this.callback = cb;
                        this.next = null;
                    } // It seems a linked list but it is not
                    // there will be only 2 of these for each stream


                    function CorkedRequest(state) {
                        var _this = this;

                        this.next = null;
                        this.entry = null;

                        this.finish = function () {
                            onCorkedFinish(_this, state);
                        };
                    }
                    /* </replacement> */

                    /*<replacement>*/


                    var Duplex;
                    /*</replacement>*/

                    Writable.WritableState = WritableState;
                    /*<replacement>*/

                    var internalUtil = {
                        deprecate: require('util-deprecate')
                    };
                    /*</replacement>*/

                    /*<replacement>*/

                    var Stream = require('./internal/streams/stream');
                    /*</replacement>*/


                    var Buffer = require('buffer').Buffer;

                    var OurUint8Array = global.Uint8Array || function () { };

                    function _uint8ArrayToBuffer(chunk) {
                        return Buffer.from(chunk);
                    }

                    function _isUint8Array(obj) {
                        return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;
                    }

                    var destroyImpl = require('./internal/streams/destroy');

                    var _require = require('./internal/streams/state'),
                        getHighWaterMark = _require.getHighWaterMark;

                    var _require$codes = require('../errors').codes,
                        ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE,
                        ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,
                        ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK,
                        ERR_STREAM_CANNOT_PIPE = _require$codes.ERR_STREAM_CANNOT_PIPE,
                        ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED,
                        ERR_STREAM_NULL_VALUES = _require$codes.ERR_STREAM_NULL_VALUES,
                        ERR_STREAM_WRITE_AFTER_END = _require$codes.ERR_STREAM_WRITE_AFTER_END,
                        ERR_UNKNOWN_ENCODING = _require$codes.ERR_UNKNOWN_ENCODING;

                    var errorOrDestroy = destroyImpl.errorOrDestroy;

                    require('inherits')(Writable, Stream);

                    function nop() { }

                    function WritableState(options, stream, isDuplex) {
                        Duplex = Duplex || require('./_stream_duplex');
                        options = options || {}; // Duplex streams are both readable and writable, but share
                        // the same options object.
                        // However, some cases require setting options to different
                        // values for the readable and the writable sides of the duplex stream,
                        // e.g. options.readableObjectMode vs. options.writableObjectMode, etc.

                        if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag to indicate whether or not this stream
                        // contains buffers or objects.

                        this.objectMode = !!options.objectMode;
                        if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode; // the point at which write() starts returning false
                        // Note: 0 is a valid value, means that we always return false if
                        // the entire buffer is not flushed immediately on write()

                        this.highWaterMark = getHighWaterMark(this, options, 'writableHighWaterMark', isDuplex); // if _final has been called

                        this.finalCalled = false; // drain event flag.

                        this.needDrain = false; // at the start of calling end()

                        this.ending = false; // when end() has been called, and returned

                        this.ended = false; // when 'finish' is emitted

                        this.finished = false; // has it been destroyed

                        this.destroyed = false; // should we decode strings into buffers before passing to _write?
                        // this is here so that some node-core streams can optimize string
                        // handling at a lower level.

                        var noDecode = options.decodeStrings === false;
                        this.decodeStrings = !noDecode; // Crypto is kind of old and crusty.  Historically, its default string
                        // encoding is 'binary' so we have to make this configurable.
                        // Everything else in the universe uses 'utf8', though.

                        this.defaultEncoding = options.defaultEncoding || 'utf8'; // not an actual buffer we keep track of, but a measurement
                        // of how much we're waiting to get pushed to some underlying
                        // socket or file.

                        this.length = 0; // a flag to see when we're in the middle of a write.

                        this.writing = false; // when true all writes will be buffered until .uncork() call

                        this.corked = 0; // a flag to be able to tell if the onwrite cb is called immediately,
                        // or on a later tick.  We set this to true at first, because any
                        // actions that shouldn't happen until "later" should generally also
                        // not happen before the first write call.

                        this.sync = true; // a flag to know if we're processing previously buffered items, which
                        // may call the _write() callback in the same tick, so that we don't
                        // end up in an overlapped onwrite situation.

                        this.bufferProcessing = false; // the callback that's passed to _write(chunk,cb)

                        this.onwrite = function (er) {
                            onwrite(stream, er);
                        }; // the callback that the user supplies to write(chunk,encoding,cb)


                        this.writecb = null; // the amount that is being written when _write is called.

                        this.writelen = 0;
                        this.bufferedRequest = null;
                        this.lastBufferedRequest = null; // number of pending user-supplied write callbacks
                        // this must be 0 before 'finish' can be emitted

                        this.pendingcb = 0; // emit prefinish if the only thing we're waiting for is _write cbs
                        // This is relevant for synchronous Transform streams

                        this.prefinished = false; // True if the error was already emitted and should not be thrown again

                        this.errorEmitted = false; // Should close be emitted on destroy. Defaults to true.

                        this.emitClose = options.emitClose !== false; // Should .destroy() be called after 'finish' (and potentially 'end')

                        this.autoDestroy = !!options.autoDestroy; // count buffered requests

                        this.bufferedRequestCount = 0; // allocate the first CorkedRequest, there is always
                        // one allocated and free to use, and we maintain at most two

                        this.corkedRequestsFree = new CorkedRequest(this);
                    }

                    WritableState.prototype.getBuffer = function getBuffer() {
                        var current = this.bufferedRequest;
                        var out = [];

                        while (current) {
                            out.push(current);
                            current = current.next;
                        }

                        return out;
                    };

                    (function () {
                        try {
                            Object.defineProperty(WritableState.prototype, 'buffer', {
                                get: internalUtil.deprecate(function writableStateBufferGetter() {
                                    return this.getBuffer();
                                }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003')
                            });
                        } catch (_) { }
                    })(); // Test _writableState for inheritance to account for Duplex streams,
                    // whose prototype chain only points to Readable.


                    var realHasInstance;

                    if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') {
                        realHasInstance = Function.prototype[Symbol.hasInstance];
                        Object.defineProperty(Writable, Symbol.hasInstance, {
                            value: function value(object) {
                                if (realHasInstance.call(this, object)) return true;
                                if (this !== Writable) return false;
                                return object && object._writableState instanceof WritableState;
                            }
                        });
                    } else {
                        realHasInstance = function realHasInstance(object) {
                            return object instanceof this;
                        };
                    }

                    function Writable(options) {
                        Duplex = Duplex || require('./_stream_duplex'); // Writable ctor is applied to Duplexes, too.
                        // `realHasInstance` is necessary because using plain `instanceof`
                        // would return false, as no `_writableState` property is attached.
                        // Trying to use the custom `instanceof` for Writable here will also break the
                        // Node.js LazyTransform implementation, which has a non-trivial getter for
                        // `_writableState` that would lead to infinite recursion.
                        // Checking for a Stream.Duplex instance is faster here instead of inside
                        // the WritableState constructor, at least with V8 6.5

                        var isDuplex = this instanceof Duplex;
                        if (!isDuplex && !realHasInstance.call(Writable, this)) return new Writable(options);
                        this._writableState = new WritableState(options, this, isDuplex); // legacy.

                        this.writable = true;

                        if (options) {
                            if (typeof options.write === 'function') this._write = options.write;
                            if (typeof options.writev === 'function') this._writev = options.writev;
                            if (typeof options.destroy === 'function') this._destroy = options.destroy;
                            if (typeof options.final === 'function') this._final = options.final;
                        }

                        Stream.call(this);
                    } // Otherwise people can pipe Writable streams, which is just wrong.


                    Writable.prototype.pipe = function () {
                        errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE());
                    };

                    function writeAfterEnd(stream, cb) {
                        var er = new ERR_STREAM_WRITE_AFTER_END(); // TODO: defer error events consistently everywhere, not just the cb

                        errorOrDestroy(stream, er);
                        process.nextTick(cb, er);
                    } // Checks that a user-supplied chunk is valid, especially for the particular
                    // mode the stream is in. Currently this means that `null` is never accepted
                    // and undefined/non-string values are only allowed in object mode.


                    function validChunk(stream, state, chunk, cb) {
                        var er;

                        if (chunk === null) {
                            er = new ERR_STREAM_NULL_VALUES();
                        } else if (typeof chunk !== 'string' && !state.objectMode) {
                            er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk);
                        }

                        if (er) {
                            errorOrDestroy(stream, er);
                            process.nextTick(cb, er);
                            return false;
                        }

                        return true;
                    }

                    Writable.prototype.write = function (chunk, encoding, cb) {
                        var state = this._writableState;
                        var ret = false;

                        var isBuf = !state.objectMode && _isUint8Array(chunk);

                        if (isBuf && !Buffer.isBuffer(chunk)) {
                            chunk = _uint8ArrayToBuffer(chunk);
                        }

                        if (typeof encoding === 'function') {
                            cb = encoding;
                            encoding = null;
                        }

                        if (isBuf) encoding = 'buffer'; else if (!encoding) encoding = state.defaultEncoding;
                        if (typeof cb !== 'function') cb = nop;
                        if (state.ending) writeAfterEnd(this, cb); else if (isBuf || validChunk(this, state, chunk, cb)) {
                            state.pendingcb++;
                            ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);
                        }
                        return ret;
                    };

                    Writable.prototype.cork = function () {
                        this._writableState.corked++;
                    };

                    Writable.prototype.uncork = function () {
                        var state = this._writableState;

                        if (state.corked) {
                            state.corked--;
                            if (!state.writing && !state.corked && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);
                        }
                    };

                    Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
                        // node::ParseEncoding() requires lower case.
                        if (typeof encoding === 'string') encoding = encoding.toLowerCase();
                        if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new ERR_UNKNOWN_ENCODING(encoding);
                        this._writableState.defaultEncoding = encoding;
                        return this;
                    };

                    Object.defineProperty(Writable.prototype, 'writableBuffer', {
                        // making it explicit this property is not enumerable
                        // because otherwise some prototype manipulation in
                        // userland will fail
                        enumerable: false,
                        get: function get() {
                            return this._writableState && this._writableState.getBuffer();
                        }
                    });

                    function decodeChunk(state, chunk, encoding) {
                        if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {
                            chunk = Buffer.from(chunk, encoding);
                        }

                        return chunk;
                    }

                    Object.defineProperty(Writable.prototype, 'writableHighWaterMark', {
                        // making it explicit this property is not enumerable
                        // because otherwise some prototype manipulation in
                        // userland will fail
                        enumerable: false,
                        get: function get() {
                            return this._writableState.highWaterMark;
                        }
                    }); // if we're already writing something, then just put this
                    // in the queue, and wait our turn.  Otherwise, call _write
                    // If we return false, then we need a drain event, so set that flag.

                    function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {
                        if (!isBuf) {
                            var newChunk = decodeChunk(state, chunk, encoding);

                            if (chunk !== newChunk) {
                                isBuf = true;
                                encoding = 'buffer';
                                chunk = newChunk;
                            }
                        }

                        var len = state.objectMode ? 1 : chunk.length;
                        state.length += len;
                        var ret = state.length < state.highWaterMark; // we must ensure that previous needDrain will not be reset to false.

                        if (!ret) state.needDrain = true;

                        if (state.writing || state.corked) {
                            var last = state.lastBufferedRequest;
                            state.lastBufferedRequest = {
                                chunk: chunk,
                                encoding: encoding,
                                isBuf: isBuf,
                                callback: cb,
                                next: null
                            };

                            if (last) {
                                last.next = state.lastBufferedRequest;
                            } else {
                                state.bufferedRequest = state.lastBufferedRequest;
                            }

                            state.bufferedRequestCount += 1;
                        } else {
                            doWrite(stream, state, false, len, chunk, encoding, cb);
                        }

                        return ret;
                    }

                    function doWrite(stream, state, writev, len, chunk, encoding, cb) {
                        state.writelen = len;
                        state.writecb = cb;
                        state.writing = true;
                        state.sync = true;
                        if (state.destroyed) state.onwrite(new ERR_STREAM_DESTROYED('write')); else if (writev) stream._writev(chunk, state.onwrite); else stream._write(chunk, encoding, state.onwrite);
                        state.sync = false;
                    }

                    function onwriteError(stream, state, sync, er, cb) {
                        --state.pendingcb;

                        if (sync) {
                            // defer the callback if we are being called synchronously
                            // to avoid piling up things on the stack
                            process.nextTick(cb, er); // this can emit finish, and it will always happen
                            // after error

                            process.nextTick(finishMaybe, stream, state);
                            stream._writableState.errorEmitted = true;
                            errorOrDestroy(stream, er);
                        } else {
                            // the caller expect this to happen before if
                            // it is async
                            cb(er);
                            stream._writableState.errorEmitted = true;
                            errorOrDestroy(stream, er); // this can emit finish, but finish must
                            // always follow error

                            finishMaybe(stream, state);
                        }
                    }

                    function onwriteStateUpdate(state) {
                        state.writing = false;
                        state.writecb = null;
                        state.length -= state.writelen;
                        state.writelen = 0;
                    }

                    function onwrite(stream, er) {
                        var state = stream._writableState;
                        var sync = state.sync;
                        var cb = state.writecb;
                        if (typeof cb !== 'function') throw new ERR_MULTIPLE_CALLBACK();
                        onwriteStateUpdate(state);
                        if (er) onwriteError(stream, state, sync, er, cb); else {
                            // Check if we're actually ready to finish, but don't emit yet
                            var finished = needFinish(state) || stream.destroyed;

                            if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {
                                clearBuffer(stream, state);
                            }

                            if (sync) {
                                process.nextTick(afterWrite, stream, state, finished, cb);
                            } else {
                                afterWrite(stream, state, finished, cb);
                            }
                        }
                    }

                    function afterWrite(stream, state, finished, cb) {
                        if (!finished) onwriteDrain(stream, state);
                        state.pendingcb--;
                        cb();
                        finishMaybe(stream, state);
                    } // Must force callback to be called on nextTick, so that we don't
                    // emit 'drain' before the write() consumer gets the 'false' return
                    // value, and has a chance to attach a 'drain' listener.


                    function onwriteDrain(stream, state) {
                        if (state.length === 0 && state.needDrain) {
                            state.needDrain = false;
                            stream.emit('drain');
                        }
                    } // if there's something in the buffer waiting, then process it


                    function clearBuffer(stream, state) {
                        state.bufferProcessing = true;
                        var entry = state.bufferedRequest;

                        if (stream._writev && entry && entry.next) {
                            // Fast case, write everything using _writev()
                            var l = state.bufferedRequestCount;
                            var buffer = new Array(l);
                            var holder = state.corkedRequestsFree;
                            holder.entry = entry;
                            var count = 0;
                            var allBuffers = true;

                            while (entry) {
                                buffer[count] = entry;
                                if (!entry.isBuf) allBuffers = false;
                                entry = entry.next;
                                count += 1;
                            }

                            buffer.allBuffers = allBuffers;
                            doWrite(stream, state, true, state.length, buffer, '', holder.finish); // doWrite is almost always async, defer these to save a bit of time
                            // as the hot path ends with doWrite

                            state.pendingcb++;
                            state.lastBufferedRequest = null;

                            if (holder.next) {
                                state.corkedRequestsFree = holder.next;
                                holder.next = null;
                            } else {
                                state.corkedRequestsFree = new CorkedRequest(state);
                            }

                            state.bufferedRequestCount = 0;
                        } else {
                            // Slow case, write chunks one-by-one
                            while (entry) {
                                var chunk = entry.chunk;
                                var encoding = entry.encoding;
                                var cb = entry.callback;
                                var len = state.objectMode ? 1 : chunk.length;
                                doWrite(stream, state, false, len, chunk, encoding, cb);
                                entry = entry.next;
                                state.bufferedRequestCount--; // if we didn't call the onwrite immediately, then
                                // it means that we need to wait until it does.
                                // also, that means that the chunk and cb are currently
                                // being processed, so move the buffer counter past them.

                                if (state.writing) {
                                    break;
                                }
                            }

                            if (entry === null) state.lastBufferedRequest = null;
                        }

                        state.bufferedRequest = entry;
                        state.bufferProcessing = false;
                    }

                    Writable.prototype._write = function (chunk, encoding, cb) {
                        cb(new ERR_METHOD_NOT_IMPLEMENTED('_write()'));
                    };

                    Writable.prototype._writev = null;

                    Writable.prototype.end = function (chunk, encoding, cb) {
                        var state = this._writableState;

                        if (typeof chunk === 'function') {
                            cb = chunk;
                            chunk = null;
                            encoding = null;
                        } else if (typeof encoding === 'function') {
                            cb = encoding;
                            encoding = null;
                        }

                        if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); // .end() fully uncorks

                        if (state.corked) {
                            state.corked = 1;
                            this.uncork();
                        } // ignore unnecessary end() calls.


                        if (!state.ending) endWritable(this, state, cb);
                        return this;
                    };

                    Object.defineProperty(Writable.prototype, 'writableLength', {
                        // making it explicit this property is not enumerable
                        // because otherwise some prototype manipulation in
                        // userland will fail
                        enumerable: false,
                        get: function get() {
                            return this._writableState.length;
                        }
                    });

                    function needFinish(state) {
                        return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;
                    }

                    function callFinal(stream, state) {
                        stream._final(function (err) {
                            state.pendingcb--;

                            if (err) {
                                errorOrDestroy(stream, err);
                            }

                            state.prefinished = true;
                            stream.emit('prefinish');
                            finishMaybe(stream, state);
                        });
                    }

                    function prefinish(stream, state) {
                        if (!state.prefinished && !state.finalCalled) {
                            if (typeof stream._final === 'function' && !state.destroyed) {
                                state.pendingcb++;
                                state.finalCalled = true;
                                process.nextTick(callFinal, stream, state);
                            } else {
                                state.prefinished = true;
                                stream.emit('prefinish');
                            }
                        }
                    }

                    function finishMaybe(stream, state) {
                        var need = needFinish(state);

                        if (need) {
                            prefinish(stream, state);

                            if (state.pendingcb === 0) {
                                state.finished = true;
                                stream.emit('finish');

                                if (state.autoDestroy) {
                                    // In case of duplex streams we need a way to detect
                                    // if the readable side is ready for autoDestroy as well
                                    var rState = stream._readableState;

                                    if (!rState || rState.autoDestroy && rState.endEmitted) {
                                        stream.destroy();
                                    }
                                }
                            }
                        }

                        return need;
                    }

                    function endWritable(stream, state, cb) {
                        state.ending = true;
                        finishMaybe(stream, state);

                        if (cb) {
                            if (state.finished) process.nextTick(cb); else stream.once('finish', cb);
                        }

                        state.ended = true;
                        stream.writable = false;
                    }

                    function onCorkedFinish(corkReq, state, err) {
                        var entry = corkReq.entry;
                        corkReq.entry = null;

                        while (entry) {
                            var cb = entry.callback;
                            state.pendingcb--;
                            cb(err);
                            entry = entry.next;
                        } // reuse the free corkReq.


                        state.corkedRequestsFree.next = corkReq;
                    }

                    Object.defineProperty(Writable.prototype, 'destroyed', {
                        // making it explicit this property is not enumerable
                        // because otherwise some prototype manipulation in
                        // userland will fail
                        enumerable: false,
                        get: function get() {
                            if (this._writableState === undefined) {
                                return false;
                            }

                            return this._writableState.destroyed;
                        },
                        set: function set(value) {
                            // we ignore the value if the stream
                            // has not been initialized yet
                            if (!this._writableState) {
                                return;
                            } // backward compatibility, the user is explicitly
                            // managing destroyed


                            this._writableState.destroyed = value;
                        }
                    });
                    Writable.prototype.destroy = destroyImpl.destroy;
                    Writable.prototype._undestroy = destroyImpl.undestroy;

                    Writable.prototype._destroy = function (err, cb) {
                        cb(err);
                    };
                }).call(this)
            }).call(this, require('_process'), typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
        }, { "../errors": 10, "./_stream_duplex": 11, "./internal/streams/destroy": 18, "./internal/streams/state": 22, "./internal/streams/stream": 23, "_process": 7, "buffer": 3, "inherits": 6, "util-deprecate": 25 }], 16: [function (require, module, exports) {
            (function (process) {
                (function () {
                    'use strict';

                    var _Object$setPrototypeO;

                    function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

                    var finished = require('./end-of-stream');

                    var kLastResolve = Symbol('lastResolve');
                    var kLastReject = Symbol('lastReject');
                    var kError = Symbol('error');
                    var kEnded = Symbol('ended');
                    var kLastPromise = Symbol('lastPromise');
                    var kHandlePromise = Symbol('handlePromise');
                    var kStream = Symbol('stream');

                    function createIterResult(value, done) {
                        return {
                            value: value,
                            done: done
                        };
                    }

                    function readAndResolve(iter) {
                        var resolve = iter[kLastResolve];

                        if (resolve !== null) {
                            var data = iter[kStream].read(); // we defer if data is null
                            // we can be expecting either 'end' or
                            // 'error'

                            if (data !== null) {
                                iter[kLastPromise] = null;
                                iter[kLastResolve] = null;
                                iter[kLastReject] = null;
                                resolve(createIterResult(data, false));
                            }
                        }
                    }

                    function onReadable(iter) {
                        // we wait for the next tick, because it might
                        // emit an error with process.nextTick
                        process.nextTick(readAndResolve, iter);
                    }

                    function wrapForNext(lastPromise, iter) {
                        return function (resolve, reject) {
                            lastPromise.then(function () {
                                if (iter[kEnded]) {
                                    resolve(createIterResult(undefined, true));
                                    return;
                                }

                                iter[kHandlePromise](resolve, reject);
                            }, reject);
                        };
                    }

                    var AsyncIteratorPrototype = Object.getPrototypeOf(function () { });
                    var ReadableStreamAsyncIteratorPrototype = Object.setPrototypeOf((_Object$setPrototypeO = {
                        get stream() {
                            return this[kStream];
                        },

                        next: function next() {
                            var _this = this;

                            // if we have detected an error in the meanwhile
                            // reject straight away
                            var error = this[kError];

                            if (error !== null) {
                                return Promise.reject(error);
                            }

                            if (this[kEnded]) {
                                return Promise.resolve(createIterResult(undefined, true));
                            }

                            if (this[kStream].destroyed) {
                                // We need to defer via nextTick because if .destroy(err) is
                                // called, the error will be emitted via nextTick, and
                                // we cannot guarantee that there is no error lingering around
                                // waiting to be emitted.
                                return new Promise(function (resolve, reject) {
                                    process.nextTick(function () {
                                        if (_this[kError]) {
                                            reject(_this[kError]);
                                        } else {
                                            resolve(createIterResult(undefined, true));
                                        }
                                    });
                                });
                            } // if we have multiple next() calls
                            // we will wait for the previous Promise to finish
                            // this logic is optimized to support for await loops,
                            // where next() is only called once at a time


                            var lastPromise = this[kLastPromise];
                            var promise;

                            if (lastPromise) {
                                promise = new Promise(wrapForNext(lastPromise, this));
                            } else {
                                // fast path needed to support multiple this.push()
                                // without triggering the next() queue
                                var data = this[kStream].read();

                                if (data !== null) {
                                    return Promise.resolve(createIterResult(data, false));
                                }

                                promise = new Promise(this[kHandlePromise]);
                            }

                            this[kLastPromise] = promise;
                            return promise;
                        }
                    }, _defineProperty(_Object$setPrototypeO, Symbol.asyncIterator, function () {
                        return this;
                    }), _defineProperty(_Object$setPrototypeO, "return", function _return() {
                        var _this2 = this;

                        // destroy(err, cb) is a private API
                        // we can guarantee we have that here, because we control the
                        // Readable class this is attached to
                        return new Promise(function (resolve, reject) {
                            _this2[kStream].destroy(null, function (err) {
                                if (err) {
                                    reject(err);
                                    return;
                                }

                                resolve(createIterResult(undefined, true));
                            });
                        });
                    }), _Object$setPrototypeO), AsyncIteratorPrototype);

                    var createReadableStreamAsyncIterator = function createReadableStreamAsyncIterator(stream) {
                        var _Object$create;

                        var iterator = Object.create(ReadableStreamAsyncIteratorPrototype, (_Object$create = {}, _defineProperty(_Object$create, kStream, {
                            value: stream,
                            writable: true
                        }), _defineProperty(_Object$create, kLastResolve, {
                            value: null,
                            writable: true
                        }), _defineProperty(_Object$create, kLastReject, {
                            value: null,
                            writable: true
                        }), _defineProperty(_Object$create, kError, {
                            value: null,
                            writable: true
                        }), _defineProperty(_Object$create, kEnded, {
                            value: stream._readableState.endEmitted,
                            writable: true
                        }), _defineProperty(_Object$create, kHandlePromise, {
                            value: function value(resolve, reject) {
                                var data = iterator[kStream].read();

                                if (data) {
                                    iterator[kLastPromise] = null;
                                    iterator[kLastResolve] = null;
                                    iterator[kLastReject] = null;
                                    resolve(createIterResult(data, false));
                                } else {
                                    iterator[kLastResolve] = resolve;
                                    iterator[kLastReject] = reject;
                                }
                            },
                            writable: true
                        }), _Object$create));
                        iterator[kLastPromise] = null;
                        finished(stream, function (err) {
                            if (err && err.code !== 'ERR_STREAM_PREMATURE_CLOSE') {
                                var reject = iterator[kLastReject]; // reject if we are waiting for data in the Promise
                                // returned by next() and store the error

                                if (reject !== null) {
                                    iterator[kLastPromise] = null;
                                    iterator[kLastResolve] = null;
                                    iterator[kLastReject] = null;
                                    reject(err);
                                }

                                iterator[kError] = err;
                                return;
                            }

                            var resolve = iterator[kLastResolve];

                            if (resolve !== null) {
                                iterator[kLastPromise] = null;
                                iterator[kLastResolve] = null;
                                iterator[kLastReject] = null;
                                resolve(createIterResult(undefined, true));
                            }

                            iterator[kEnded] = true;
                        });
                        stream.on('readable', onReadable.bind(null, iterator));
                        return iterator;
                    };

                    module.exports = createReadableStreamAsyncIterator;
                }).call(this)
            }).call(this, require('_process'))
        }, { "./end-of-stream": 19, "_process": 7 }], 17: [function (require, module, exports) {
            'use strict';

            function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

            function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

            function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

            function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

            function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

            var _require = require('buffer'),
                Buffer = _require.Buffer;

            var _require2 = require('util'),
                inspect = _require2.inspect;

            var custom = inspect && inspect.custom || 'inspect';

            function copyBuffer(src, target, offset) {
                Buffer.prototype.copy.call(src, target, offset);
            }

            module.exports =
                /*#__PURE__*/
                function () {
                    function BufferList() {
                        _classCallCheck(this, BufferList);

                        this.head = null;
                        this.tail = null;
                        this.length = 0;
                    }

                    _createClass(BufferList, [{
                        key: "push",
                        value: function push(v) {
                            var entry = {
                                data: v,
                                next: null
                            };
                            if (this.length > 0) this.tail.next = entry; else this.head = entry;
                            this.tail = entry;
                            ++this.length;
                        }
                    }, {
                        key: "unshift",
                        value: function unshift(v) {
                            var entry = {
                                data: v,
                                next: this.head
                            };
                            if (this.length === 0) this.tail = entry;
                            this.head = entry;
                            ++this.length;
                        }
                    }, {
                        key: "shift",
                        value: function shift() {
                            if (this.length === 0) return;
                            var ret = this.head.data;
                            if (this.length === 1) this.head = this.tail = null; else this.head = this.head.next;
                            --this.length;
                            return ret;
                        }
                    }, {
                        key: "clear",
                        value: function clear() {
                            this.head = this.tail = null;
                            this.length = 0;
                        }
                    }, {
                        key: "join",
                        value: function join(s) {
                            if (this.length === 0) return '';
                            var p = this.head;
                            var ret = '' + p.data;

                            while (p = p.next) {
                                ret += s + p.data;
                            }

                            return ret;
                        }
                    }, {
                        key: "concat",
                        value: function concat(n) {
                            if (this.length === 0) return Buffer.alloc(0);
                            var ret = Buffer.allocUnsafe(n >>> 0);
                            var p = this.head;
                            var i = 0;

                            while (p) {
                                copyBuffer(p.data, ret, i);
                                i += p.data.length;
                                p = p.next;
                            }

                            return ret;
                        } // Consumes a specified amount of bytes or characters from the buffered data.

                    }, {
                        key: "consume",
                        value: function consume(n, hasStrings) {
                            var ret;

                            if (n < this.head.data.length) {
                                // `slice` is the same for buffers and strings.
                                ret = this.head.data.slice(0, n);
                                this.head.data = this.head.data.slice(n);
                            } else if (n === this.head.data.length) {
                                // First chunk is a perfect match.
                                ret = this.shift();
                            } else {
                                // Result spans more than one buffer.
                                ret = hasStrings ? this._getString(n) : this._getBuffer(n);
                            }

                            return ret;
                        }
                    }, {
                        key: "first",
                        value: function first() {
                            return this.head.data;
                        } // Consumes a specified amount of characters from the buffered data.

                    }, {
                        key: "_getString",
                        value: function _getString(n) {
                            var p = this.head;
                            var c = 1;
                            var ret = p.data;
                            n -= ret.length;

                            while (p = p.next) {
                                var str = p.data;
                                var nb = n > str.length ? str.length : n;
                                if (nb === str.length) ret += str; else ret += str.slice(0, n);
                                n -= nb;

                                if (n === 0) {
                                    if (nb === str.length) {
                                        ++c;
                                        if (p.next) this.head = p.next; else this.head = this.tail = null;
                                    } else {
                                        this.head = p;
                                        p.data = str.slice(nb);
                                    }

                                    break;
                                }

                                ++c;
                            }

                            this.length -= c;
                            return ret;
                        } // Consumes a specified amount of bytes from the buffered data.

                    }, {
                        key: "_getBuffer",
                        value: function _getBuffer(n) {
                            var ret = Buffer.allocUnsafe(n);
                            var p = this.head;
                            var c = 1;
                            p.data.copy(ret);
                            n -= p.data.length;

                            while (p = p.next) {
                                var buf = p.data;
                                var nb = n > buf.length ? buf.length : n;
                                buf.copy(ret, ret.length - n, 0, nb);
                                n -= nb;

                                if (n === 0) {
                                    if (nb === buf.length) {
                                        ++c;
                                        if (p.next) this.head = p.next; else this.head = this.tail = null;
                                    } else {
                                        this.head = p;
                                        p.data = buf.slice(nb);
                                    }

                                    break;
                                }

                                ++c;
                            }

                            this.length -= c;
                            return ret;
                        } // Make sure the linked list only shows the minimal necessary information.

                    }, {
                        key: custom,
                        value: function value(_, options) {
                            return inspect(this, _objectSpread({}, options, {
                                // Only inspect one level.
                                depth: 0,
                                // It should not recurse.
                                customInspect: false
                            }));
                        }
                    }]);

                    return BufferList;
                }();
        }, { "buffer": 3, "util": 2 }], 18: [function (require, module, exports) {
            (function (process) {
                (function () {
                    'use strict'; // undocumented cb() API, needed for core, not for public API

                    function destroy(err, cb) {
                        var _this = this;

                        var readableDestroyed = this._readableState && this._readableState.destroyed;
                        var writableDestroyed = this._writableState && this._writableState.destroyed;

                        if (readableDestroyed || writableDestroyed) {
                            if (cb) {
                                cb(err);
                            } else if (err) {
                                if (!this._writableState) {
                                    process.nextTick(emitErrorNT, this, err);
                                } else if (!this._writableState.errorEmitted) {
                                    this._writableState.errorEmitted = true;
                                    process.nextTick(emitErrorNT, this, err);
                                }
                            }

                            return this;
                        } // we set destroyed to true before firing error callbacks in order
                        // to make it re-entrance safe in case destroy() is called within callbacks


                        if (this._readableState) {
                            this._readableState.destroyed = true;
                        } // if this is a duplex stream mark the writable part as destroyed as well


                        if (this._writableState) {
                            this._writableState.destroyed = true;
                        }

                        this._destroy(err || null, function (err) {
                            if (!cb && err) {
                                if (!_this._writableState) {
                                    process.nextTick(emitErrorAndCloseNT, _this, err);
                                } else if (!_this._writableState.errorEmitted) {
                                    _this._writableState.errorEmitted = true;
                                    process.nextTick(emitErrorAndCloseNT, _this, err);
                                } else {
                                    process.nextTick(emitCloseNT, _this);
                                }
                            } else if (cb) {
                                process.nextTick(emitCloseNT, _this);
                                cb(err);
                            } else {
                                process.nextTick(emitCloseNT, _this);
                            }
                        });

                        return this;
                    }

                    function emitErrorAndCloseNT(self, err) {
                        emitErrorNT(self, err);
                        emitCloseNT(self);
                    }

                    function emitCloseNT(self) {
                        if (self._writableState && !self._writableState.emitClose) return;
                        if (self._readableState && !self._readableState.emitClose) return;
                        self.emit('close');
                    }

                    function undestroy() {
                        if (this._readableState) {
                            this._readableState.destroyed = false;
                            this._readableState.reading = false;
                            this._readableState.ended = false;
                            this._readableState.endEmitted = false;
                        }

                        if (this._writableState) {
                            this._writableState.destroyed = false;
                            this._writableState.ended = false;
                            this._writableState.ending = false;
                            this._writableState.finalCalled = false;
                            this._writableState.prefinished = false;
                            this._writableState.finished = false;
                            this._writableState.errorEmitted = false;
                        }
                    }

                    function emitErrorNT(self, err) {
                        self.emit('error', err);
                    }

                    function errorOrDestroy(stream, err) {
                        // We have tests that rely on errors being emitted
                        // in the same tick, so changing this is semver major.
                        // For now when you opt-in to autoDestroy we allow
                        // the error to be emitted nextTick. In a future
                        // semver major update we should change the default to this.
                        var rState = stream._readableState;
                        var wState = stream._writableState;
                        if (rState && rState.autoDestroy || wState && wState.autoDestroy) stream.destroy(err); else stream.emit('error', err);
                    }

                    module.exports = {
                        destroy: destroy,
                        undestroy: undestroy,
                        errorOrDestroy: errorOrDestroy
                    };
                }).call(this)
            }).call(this, require('_process'))
        }, { "_process": 7 }], 19: [function (require, module, exports) {
            // Ported from https://github.com/mafintosh/end-of-stream with
            // permission from the author, Mathias Buus (@mafintosh).
            'use strict';

            var ERR_STREAM_PREMATURE_CLOSE = require('../../../errors').codes.ERR_STREAM_PREMATURE_CLOSE;

            function once(callback) {
                var called = false;
                return function () {
                    if (called) return;
                    called = true;

                    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
                        args[_key] = arguments[_key];
                    }

                    callback.apply(this, args);
                };
            }

            function noop() { }

            function isRequest(stream) {
                return stream.setHeader && typeof stream.abort === 'function';
            }

            function eos(stream, opts, callback) {
                if (typeof opts === 'function') return eos(stream, null, opts);
                if (!opts) opts = {};
                callback = once(callback || noop);
                var readable = opts.readable || opts.readable !== false && stream.readable;
                var writable = opts.writable || opts.writable !== false && stream.writable;

                var onlegacyfinish = function onlegacyfinish() {
                    if (!stream.writable) onfinish();
                };

                var writableEnded = stream._writableState && stream._writableState.finished;

                var onfinish = function onfinish() {
                    writable = false;
                    writableEnded = true;
                    if (!readable) callback.call(stream);
                };

                var readableEnded = stream._readableState && stream._readableState.endEmitted;

                var onend = function onend() {
                    readable = false;
                    readableEnded = true;
                    if (!writable) callback.call(stream);
                };

                var onerror = function onerror(err) {
                    callback.call(stream, err);
                };

                var onclose = function onclose() {
                    var err;

                    if (readable && !readableEnded) {
                        if (!stream._readableState || !stream._readableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE();
                        return callback.call(stream, err);
                    }

                    if (writable && !writableEnded) {
                        if (!stream._writableState || !stream._writableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE();
                        return callback.call(stream, err);
                    }
                };

                var onrequest = function onrequest() {
                    stream.req.on('finish', onfinish);
                };

                if (isRequest(stream)) {
                    stream.on('complete', onfinish);
                    stream.on('abort', onclose);
                    if (stream.req) onrequest(); else stream.on('request', onrequest);
                } else if (writable && !stream._writableState) {
                    // legacy streams
                    stream.on('end', onlegacyfinish);
                    stream.on('close', onlegacyfinish);
                }

                stream.on('end', onend);
                stream.on('finish', onfinish);
                if (opts.error !== false) stream.on('error', onerror);
                stream.on('close', onclose);
                return function () {
                    stream.removeListener('complete', onfinish);
                    stream.removeListener('abort', onclose);
                    stream.removeListener('request', onrequest);
                    if (stream.req) stream.req.removeListener('finish', onfinish);
                    stream.removeListener('end', onlegacyfinish);
                    stream.removeListener('close', onlegacyfinish);
                    stream.removeListener('finish', onfinish);
                    stream.removeListener('end', onend);
                    stream.removeListener('error', onerror);
                    stream.removeListener('close', onclose);
                };
            }

            module.exports = eos;
        }, { "../../../errors": 10 }], 20: [function (require, module, exports) {
            module.exports = function () {
                throw new Error('Readable.from is not available in the browser')
            };

        }, {}], 21: [function (require, module, exports) {
            // Ported from https://github.com/mafintosh/pump with
            // permission from the author, Mathias Buus (@mafintosh).
            'use strict';

            var eos;

            function once(callback) {
                var called = false;
                return function () {
                    if (called) return;
                    called = true;
                    callback.apply(void 0, arguments);
                };
            }

            var _require$codes = require('../../../errors').codes,
                ERR_MISSING_ARGS = _require$codes.ERR_MISSING_ARGS,
                ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED;

            function noop(err) {
                // Rethrow the error if it exists to avoid swallowing it
                if (err) throw err;
            }

            function isRequest(stream) {
                return stream.setHeader && typeof stream.abort === 'function';
            }

            function destroyer(stream, reading, writing, callback) {
                callback = once(callback);
                var closed = false;
                stream.on('close', function () {
                    closed = true;
                });
                if (eos === undefined) eos = require('./end-of-stream');
                eos(stream, {
                    readable: reading,
                    writable: writing
                }, function (err) {
                    if (err) return callback(err);
                    closed = true;
                    callback();
                });
                var destroyed = false;
                return function (err) {
                    if (closed) return;
                    if (destroyed) return;
                    destroyed = true; // request.destroy just do .end - .abort is what we want

                    if (isRequest(stream)) return stream.abort();
                    if (typeof stream.destroy === 'function') return stream.destroy();
                    callback(err || new ERR_STREAM_DESTROYED('pipe'));
                };
            }

            function call(fn) {
                fn();
            }

            function pipe(from, to) {
                return from.pipe(to);
            }

            function popCallback(streams) {
                if (!streams.length) return noop;
                if (typeof streams[streams.length - 1] !== 'function') return noop;
                return streams.pop();
            }

            function pipeline() {
                for (var _len = arguments.length, streams = new Array(_len), _key = 0; _key < _len; _key++) {
                    streams[_key] = arguments[_key];
                }

                var callback = popCallback(streams);
                if (Array.isArray(streams[0])) streams = streams[0];

                if (streams.length < 2) {
                    throw new ERR_MISSING_ARGS('streams');
                }

                var error;
                var destroys = streams.map(function (stream, i) {
                    var reading = i < streams.length - 1;
                    var writing = i > 0;
                    return destroyer(stream, reading, writing, function (err) {
                        if (!error) error = err;
                        if (err) destroys.forEach(call);
                        if (reading) return;
                        destroys.forEach(call);
                        callback(error);
                    });
                });
                return streams.reduce(pipe);
            }

            module.exports = pipeline;
        }, { "../../../errors": 10, "./end-of-stream": 19 }], 22: [function (require, module, exports) {
            'use strict';

            var ERR_INVALID_OPT_VALUE = require('../../../errors').codes.ERR_INVALID_OPT_VALUE;

            function highWaterMarkFrom(options, isDuplex, duplexKey) {
                return options.highWaterMark != null ? options.highWaterMark : isDuplex ? options[duplexKey] : null;
            }

            function getHighWaterMark(state, options, duplexKey, isDuplex) {
                var hwm = highWaterMarkFrom(options, isDuplex, duplexKey);

                if (hwm != null) {
                    if (!(isFinite(hwm) && Math.floor(hwm) === hwm) || hwm < 0) {
                        var name = isDuplex ? duplexKey : 'highWaterMark';
                        throw new ERR_INVALID_OPT_VALUE(name, hwm);
                    }

                    return Math.floor(hwm);
                } // Default value


                return state.objectMode ? 16 : 16 * 1024;
            }

            module.exports = {
                getHighWaterMark: getHighWaterMark
            };
        }, { "../../../errors": 10 }], 23: [function (require, module, exports) {
            module.exports = require('events').EventEmitter;

        }, { "events": 4 }], 24: [function (require, module, exports) {
            // Copyright Joyent, Inc. and other Node contributors.
            //
            // Permission is hereby granted, free of charge, to any person obtaining a
            // copy of this software and associated documentation files (the
            // "Software"), to deal in the Software without restriction, including
            // without limitation the rights to use, copy, modify, merge, publish,
            // distribute, sublicense, and/or sell copies of the Software, and to permit
            // persons to whom the Software is furnished to do so, subject to the
            // following conditions:
            //
            // The above copyright notice and this permission notice shall be included
            // in all copies or substantial portions of the Software.
            //
            // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
            // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
            // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
            // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
            // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
            // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
            // USE OR OTHER DEALINGS IN THE SOFTWARE.

            'use strict';

            /*<replacement>*/

            var Buffer = require('safe-buffer').Buffer;
            /*</replacement>*/

            var isEncoding = Buffer.isEncoding || function (encoding) {
                encoding = '' + encoding;
                switch (encoding && encoding.toLowerCase()) {
                    case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw':
                        return true;
                    default:
                        return false;
                }
            };

            function _normalizeEncoding(enc) {
                if (!enc) return 'utf8';
                var retried;
                while (true) {
                    switch (enc) {
                        case 'utf8':
                        case 'utf-8':
                            return 'utf8';
                        case 'ucs2':
                        case 'ucs-2':
                        case 'utf16le':
                        case 'utf-16le':
                            return 'utf16le';
                        case 'latin1':
                        case 'binary':
                            return 'latin1';
                        case 'base64':
                        case 'ascii':
                        case 'hex':
                            return enc;
                        default:
                            if (retried) return; // undefined
                            enc = ('' + enc).toLowerCase();
                            retried = true;
                    }
                }
            };

            // Do not cache `Buffer.isEncoding` when checking encoding names as some
            // modules monkey-patch it to support additional encodings
            function normalizeEncoding(enc) {
                var nenc = _normalizeEncoding(enc);
                if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc);
                return nenc || enc;
            }

            // StringDecoder provides an interface for efficiently splitting a series of
            // buffers into a series of JS strings without breaking apart multi-byte
            // characters.
            exports.StringDecoder = StringDecoder;
            function StringDecoder(encoding) {
                this.encoding = normalizeEncoding(encoding);
                var nb;
                switch (this.encoding) {
                    case 'utf16le':
                        this.text = utf16Text;
                        this.end = utf16End;
                        nb = 4;
                        break;
                    case 'utf8':
                        this.fillLast = utf8FillLast;
                        nb = 4;
                        break;
                    case 'base64':
                        this.text = base64Text;
                        this.end = base64End;
                        nb = 3;
                        break;
                    default:
                        this.write = simpleWrite;
                        this.end = simpleEnd;
                        return;
                }
                this.lastNeed = 0;
                this.lastTotal = 0;
                this.lastChar = Buffer.allocUnsafe(nb);
            }

            StringDecoder.prototype.write = function (buf) {
                if (buf.length === 0) return '';
                var r;
                var i;
                if (this.lastNeed) {
                    r = this.fillLast(buf);
                    if (r === undefined) return '';
                    i = this.lastNeed;
                    this.lastNeed = 0;
                } else {
                    i = 0;
                }
                if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i);
                return r || '';
            };

            StringDecoder.prototype.end = utf8End;

            // Returns only complete characters in a Buffer
            StringDecoder.prototype.text = utf8Text;

            // Attempts to complete a partial non-UTF-8 character using bytes from a Buffer
            StringDecoder.prototype.fillLast = function (buf) {
                if (this.lastNeed <= buf.length) {
                    buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed);
                    return this.lastChar.toString(this.encoding, 0, this.lastTotal);
                }
                buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length);
                this.lastNeed -= buf.length;
            };

            // Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a
            // continuation byte. If an invalid byte is detected, -2 is returned.
            function utf8CheckByte(byte) {
                if (byte <= 0x7F) return 0; else if (byte >> 5 === 0x06) return 2; else if (byte >> 4 === 0x0E) return 3; else if (byte >> 3 === 0x1E) return 4;
                return byte >> 6 === 0x02 ? -1 : -2;
            }

            // Checks at most 3 bytes at the end of a Buffer in order to detect an
            // incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4)
            // needed to complete the UTF-8 character (if applicable) are returned.
            function utf8CheckIncomplete(self, buf, i) {
                var j = buf.length - 1;
                if (j < i) return 0;
                var nb = utf8CheckByte(buf[j]);
                if (nb >= 0) {
                    if (nb > 0) self.lastNeed = nb - 1;
                    return nb;
                }
                if (--j < i || nb === -2) return 0;
                nb = utf8CheckByte(buf[j]);
                if (nb >= 0) {
                    if (nb > 0) self.lastNeed = nb - 2;
                    return nb;
                }
                if (--j < i || nb === -2) return 0;
                nb = utf8CheckByte(buf[j]);
                if (nb >= 0) {
                    if (nb > 0) {
                        if (nb === 2) nb = 0; else self.lastNeed = nb - 3;
                    }
                    return nb;
                }
                return 0;
            }

            // Validates as many continuation bytes for a multi-byte UTF-8 character as
            // needed or are available. If we see a non-continuation byte where we expect
            // one, we "replace" the validated continuation bytes we've seen so far with
            // a single UTF-8 replacement character ('\ufffd'), to match v8's UTF-8 decoding
            // behavior. The continuation byte check is included three times in the case
            // where all of the continuation bytes for a character exist in the same buffer.
            // It is also done this way as a slight performance increase instead of using a
            // loop.
            function utf8CheckExtraBytes(self, buf, p) {
                if ((buf[0] & 0xC0) !== 0x80) {
                    self.lastNeed = 0;
                    return '\ufffd';
                }
                if (self.lastNeed > 1 && buf.length > 1) {
                    if ((buf[1] & 0xC0) !== 0x80) {
                        self.lastNeed = 1;
                        return '\ufffd';
                    }
                    if (self.lastNeed > 2 && buf.length > 2) {
                        if ((buf[2] & 0xC0) !== 0x80) {
                            self.lastNeed = 2;
                            return '\ufffd';
                        }
                    }
                }
            }

            // Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer.
            function utf8FillLast(buf) {
                var p = this.lastTotal - this.lastNeed;
                var r = utf8CheckExtraBytes(this, buf, p);
                if (r !== undefined) return r;
                if (this.lastNeed <= buf.length) {
                    buf.copy(this.lastChar, p, 0, this.lastNeed);
                    return this.lastChar.toString(this.encoding, 0, this.lastTotal);
                }
                buf.copy(this.lastChar, p, 0, buf.length);
                this.lastNeed -= buf.length;
            }

            // Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a
            // partial character, the character's bytes are buffered until the required
            // number of bytes are available.
            function utf8Text(buf, i) {
                var total = utf8CheckIncomplete(this, buf, i);
                if (!this.lastNeed) return buf.toString('utf8', i);
                this.lastTotal = total;
                var end = buf.length - (total - this.lastNeed);
                buf.copy(this.lastChar, 0, end);
                return buf.toString('utf8', i, end);
            }

            // For UTF-8, a replacement character is added when ending on a partial
            // character.
            function utf8End(buf) {
                var r = buf && buf.length ? this.write(buf) : '';
                if (this.lastNeed) return r + '\ufffd';
                return r;
            }

            // UTF-16LE typically needs two bytes per character, but even if we have an even
            // number of bytes available, we need to check if we end on a leading/high
            // surrogate. In that case, we need to wait for the next two bytes in order to
            // decode the last character properly.
            function utf16Text(buf, i) {
                if ((buf.length - i) % 2 === 0) {
                    var r = buf.toString('utf16le', i);
                    if (r) {
                        var c = r.charCodeAt(r.length - 1);
                        if (c >= 0xD800 && c <= 0xDBFF) {
                            this.lastNeed = 2;
                            this.lastTotal = 4;
                            this.lastChar[0] = buf[buf.length - 2];
                            this.lastChar[1] = buf[buf.length - 1];
                            return r.slice(0, -1);
                        }
                    }
                    return r;
                }
                this.lastNeed = 1;
                this.lastTotal = 2;
                this.lastChar[0] = buf[buf.length - 1];
                return buf.toString('utf16le', i, buf.length - 1);
            }

            // For UTF-16LE we do not explicitly append special replacement characters if we
            // end on a partial character, we simply let v8 handle that.
            function utf16End(buf) {
                var r = buf && buf.length ? this.write(buf) : '';
                if (this.lastNeed) {
                    var end = this.lastTotal - this.lastNeed;
                    return r + this.lastChar.toString('utf16le', 0, end);
                }
                return r;
            }

            function base64Text(buf, i) {
                var n = (buf.length - i) % 3;
                if (n === 0) return buf.toString('base64', i);
                this.lastNeed = 3 - n;
                this.lastTotal = 3;
                if (n === 1) {
                    this.lastChar[0] = buf[buf.length - 1];
                } else {
                    this.lastChar[0] = buf[buf.length - 2];
                    this.lastChar[1] = buf[buf.length - 1];
                }
                return buf.toString('base64', i, buf.length - n);
            }

            function base64End(buf) {
                var r = buf && buf.length ? this.write(buf) : '';
                if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed);
                return r;
            }

            // Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex)
            function simpleWrite(buf) {
                return buf.toString(this.encoding);
            }

            function simpleEnd(buf) {
                return buf && buf.length ? this.write(buf) : '';
            }
        }, { "safe-buffer": 8 }], 25: [function (require, module, exports) {
            (function (global) {
                (function () {

                    /**
                     * Module exports.
                     */

                    module.exports = deprecate;

                    /**
                     * Mark that a method should not be used.
                     * Returns a modified function which warns once by default.
                     *
                     * If `localStorage.noDeprecation = true` is set, then it is a no-op.
                     *
                     * If `localStorage.throwDeprecation = true` is set, then deprecated functions
                     * will throw an Error when invoked.
                     *
                     * If `localStorage.traceDeprecation = true` is set, then deprecated functions
                     * will invoke `console.trace()` instead of `console.error()`.
                     *
                     * @param {Function} fn - the function to deprecate
                     * @param {String} msg - the string to print to the console when `fn` is invoked
                     * @returns {Function} a new "deprecated" version of `fn`
                     * @api public
                     */

                    function deprecate(fn, msg) {
                        if (config('noDeprecation')) {
                            return fn;
                        }

                        var warned = false;
                        function deprecated() {
                            if (!warned) {
                                if (config('throwDeprecation')) {
                                    throw new Error(msg);
                                } else if (config('traceDeprecation')) {
                                    console.trace(msg);
                                } else {
                                    console.warn(msg);
                                }
                                warned = true;
                            }
                            return fn.apply(this, arguments);
                        }

                        return deprecated;
                    }

                    /**
                     * Checks `localStorage` for boolean values for the given `name`.
                     *
                     * @param {String} name
                     * @returns {Boolean}
                     * @api private
                     */

                    function config(name) {
                        // accessing global.localStorage can trigger a DOMException in sandboxed iframes
                        try {
                            if (!global.localStorage) return false;
                        } catch (_) {
                            return false;
                        }
                        var val = global.localStorage[name];
                        if (null == val) return false;
                        return String(val).toLowerCase() === 'true';
                    }

                }).call(this)
            }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
        }, {}], 26: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            var FlatModule_1 = require("./FlatModule");
            var YosysModel_1 = require("./YosysModel");
            var Skin_1 = require("./Skin");
            var Port_1 = require("./Port");
            var _ = require("lodash");
            var clone = require("clone");
            var onml = require("onml");
            var Cell = /** @class */ (function () {
                function Cell(key, type, inputPorts, outputPorts, attributes) {
                    var _this = this;
                    this.key = key;
                    this.type = type;
                    this.inputPorts = inputPorts;
                    this.outputPorts = outputPorts;
                    this.attributes = attributes || {};
                    inputPorts.forEach(function (ip) {
                        ip.parentNode = _this;
                    });
                    outputPorts.forEach(function (op) {
                        op.parentNode = _this;
                    });
                }
                /**
                 * creates a Cell from a Yosys Port
                 * @param yPort the Yosys Port with our port data
                 * @param name the name of the port
                 */
                Cell.fromPort = function (yPort, name) {
                    var isInput = yPort.direction === YosysModel_1.default.Direction.Input;
                    if (isInput) {
                        return new Cell(name, '$_inputExt_', [], [new Port_1.Port('Y', yPort.bits)], {});
                    }
                    return new Cell(name, '$_outputExt_', [new Port_1.Port('A', yPort.bits)], [], {});
                };
                Cell.fromYosysCell = function (yCell, name) {
                    this.setAlternateCellType(yCell);
                    var template = Skin_1.default.findSkinType(yCell.type);
                    var templateInputPids = Skin_1.default.getInputPids(template);
                    var templateOutputPids = Skin_1.default.getOutputPids(template);
                    var ports = _.map(yCell.connections, function (conn, portName) {
                        return new Port_1.Port(portName, conn);
                    });
                    var inputPorts = ports.filter(function (port) { return port.keyIn(templateInputPids); });
                    var outputPorts = ports.filter(function (port) { return port.keyIn(templateOutputPids); });
                    if (inputPorts.length + outputPorts.length !== ports.length) {
                        var inputPids_1 = YosysModel_1.default.getInputPortPids(yCell);
                        var outputPids_1 = YosysModel_1.default.getOutputPortPids(yCell);
                        inputPorts = ports.filter(function (port) { return port.keyIn(inputPids_1); });
                        outputPorts = ports.filter(function (port) { return port.keyIn(outputPids_1); });
                    }
                    return new Cell(name, yCell.type, inputPorts, outputPorts, yCell.attributes);
                };
                Cell.fromConstantInfo = function (name, constants) {
                    return new Cell(name, '$_constant_', [], [new Port_1.Port('Y', constants)], {});
                };
                /**
                 * creates a join cell
                 * @param target string name of net (starts and ends with and delimited by commas)
                 * @param sources list of index strings (one number, or two numbers separated by a colon)
                 */
                Cell.fromJoinInfo = function (target, sources) {
                    var signalStrs = target.slice(1, -1).split(',');
                    var signals = signalStrs.map(function (ss) { return Number(ss); });
                    var joinOutPorts = [new Port_1.Port('Y', signals)];
                    var inPorts = sources.map(function (name) {
                        return new Port_1.Port(name, getBits(signals, name));
                    });
                    return new Cell('$join$' + target, '$_join_', inPorts, joinOutPorts, {});
                };
                /**
                 * creates a split cell
                 * @param source string name of net (starts and ends with and delimited by commas)
                 * @param targets list of index strings (one number, or two numbers separated by a colon)
                 */
                Cell.fromSplitInfo = function (source, targets) {
                    // turn string into array of signal names
                    var sigStrs = source.slice(1, -1).split(',');
                    // convert the signals into actual numbers
                    // after running constant pass, all signals should be numbers
                    var signals = sigStrs.map(function (s) { return Number(s); });
                    var inPorts = [new Port_1.Port('A', signals)];
                    var splitOutPorts = targets.map(function (name) {
                        var sigs = getBits(signals, name);
                        return new Port_1.Port(name, sigs);
                    });
                    return new Cell('$split$' + source, '$_split_', inPorts, splitOutPorts, {});
                };
                // Set cells to alternate types/tags based on their parameters
                Cell.setAlternateCellType = function (yCell) {
                    if ('parameters' in yCell) {
                        // if it has a WIDTH parameter greater than one
                        // and doesn't have an address parameter (not a memory cell)
                        if ('WIDTH' in yCell.parameters &&
                            yCell.parameters.WIDTH > 1 &&
                            !('ADDR' in yCell.parameters)) {
                            // turn into a bus version
                            yCell.type = yCell.type + '-bus';
                        }
                    }
                };
                Object.defineProperty(Cell.prototype, "Type", {
                    get: function () {
                        return this.type;
                    },
                    enumerable: false,
                    configurable: true
                });
                Object.defineProperty(Cell.prototype, "Key", {
                    get: function () {
                        return this.key;
                    },
                    enumerable: false,
                    configurable: true
                });
                Object.defineProperty(Cell.prototype, "InputPorts", {
                    get: function () {
                        return this.inputPorts;
                    },
                    enumerable: false,
                    configurable: true
                });
                Object.defineProperty(Cell.prototype, "OutputPorts", {
                    get: function () {
                        return this.outputPorts;
                    },
                    enumerable: false,
                    configurable: true
                });
                Cell.prototype.maxOutVal = function (atLeast) {
                    var maxVal = _.max(this.outputPorts.map(function (op) { return op.maxVal(); }));
                    return _.max([maxVal, atLeast]);
                };
                Cell.prototype.findConstants = function (sigsByConstantName, maxNum, constantCollector) {
                    this.inputPorts.forEach(function (ip) {
                        maxNum = ip.findConstants(sigsByConstantName, maxNum, constantCollector);
                    });
                    return maxNum;
                };
                Cell.prototype.inputPortVals = function () {
                    return this.inputPorts.map(function (port) { return port.valString(); });
                };
                Cell.prototype.outputPortVals = function () {
                    return this.outputPorts.map(function (port) { return port.valString(); });
                };
                Cell.prototype.collectPortsByDirection = function (ridersByNet, driversByNet, lateralsByNet, genericsLaterals) {
                    var template = Skin_1.default.findSkinType(this.type);
                    var lateralPids = Skin_1.default.getLateralPortPids(template);
                    // find all ports connected to the same net
                    this.inputPorts.forEach(function (port) {
                        var isLateral = port.keyIn(lateralPids);
                        if (isLateral || (template[1]['s:type'] === 'generic' && genericsLaterals)) {
                            FlatModule_1.addToDefaultDict(lateralsByNet, port.valString(), port);
                        }
                        else {
                            FlatModule_1.addToDefaultDict(ridersByNet, port.valString(), port);
                        }
                    });
                    this.outputPorts.forEach(function (port) {
                        var isLateral = port.keyIn(lateralPids);
                        if (isLateral || (template[1]['s:type'] === 'generic' && genericsLaterals)) {
                            FlatModule_1.addToDefaultDict(lateralsByNet, port.valString(), port);
                        }
                        else {
                            FlatModule_1.addToDefaultDict(driversByNet, port.valString(), port);
                        }
                    });
                };
                Cell.prototype.getValueAttribute = function () {
                    if (this.attributes && this.attributes.value) {
                        return this.attributes.value;
                    }
                    return null;
                };
                Cell.prototype.getTemplate = function () {
                    return Skin_1.default.findSkinType(this.type);
                };
                Cell.prototype.buildElkChild = function () {
                    var _this = this;
                    var template = this.getTemplate();
                    var type = template[1]['s:type'];
                    var layoutAttrs = { 'org.eclipse.elk.portConstraints': 'FIXED_POS' };
                    var fixedPosX = null;
                    var fixedPosY = null;
                    for (var attr in this.attributes) {
                        if (attr.startsWith('org.eclipse.elk')) {
                            if (attr === 'org.eclipse.elk.x') {
                                fixedPosX = this.attributes[attr];
                                continue;
                            }
                            if (attr === 'org.eclipse.elk.y') {
                                fixedPosY = this.attributes[attr];
                                continue;
                            }
                            layoutAttrs[attr] = this.attributes[attr];
                        }
                    }
                    if (type === 'join' ||
                        type === 'split' ||
                        type === 'generic') {
                        var inTemplates_1 = Skin_1.default.getPortsWithPrefix(template, 'in');
                        var outTemplates_1 = Skin_1.default.getPortsWithPrefix(template, 'out');
                        var inPorts = this.inputPorts.map(function (ip, i) {
                            return ip.getGenericElkPort(i, inTemplates_1, 'in');
                        });
                        var outPorts = this.outputPorts.map(function (op, i) {
                            return op.getGenericElkPort(i, outTemplates_1, 'out');
                        });
                        var cell = {
                            id: this.key,
                            width: Number(template[1]['s:width']),
                            height: Number(this.getGenericHeight()),
                            ports: inPorts.concat(outPorts),
                            layoutOptions: layoutAttrs,
                            labels: [],
                        };
                        if (fixedPosX) {
                            cell.x = fixedPosX;
                        }
                        if (fixedPosY) {
                            cell.y = fixedPosY;
                        }
                        this.addLabels(template, cell);
                        return cell;
                    }
                    var ports = Skin_1.default.getPortsWithPrefix(template, '').map(function (tp) {
                        return {
                            id: _this.key + '.' + tp[1]['s:pid'],
                            width: 0,
                            height: 0,
                            x: Number(tp[1]['s:x']),
                            y: Number(tp[1]['s:y']),
                        };
                    });
                    var nodeWidth = Number(template[1]['s:width']);
                    var ret = {
                        id: this.key,
                        width: nodeWidth,
                        height: Number(template[1]['s:height']),
                        ports: ports,
                        layoutOptions: layoutAttrs,
                        labels: [],
                    };
                    if (fixedPosX) {
                        ret.x = fixedPosX;
                    }
                    if (fixedPosY) {
                        ret.y = fixedPosY;
                    }
                    this.addLabels(template, ret);
                    return ret;
                };
                Cell.prototype.render = function (cell) {
                    var template = this.getTemplate();
                    var tempclone = clone(template);
                    for (var _i = 0, _a = cell.labels; _i < _a.length; _i++) {
                        var label = _a[_i];
                        var labelIDSplit = label.id.split('.');
                        var attrName = labelIDSplit[labelIDSplit.length - 1];
                        setTextAttribute(tempclone, attrName, label.text);
                    }
                    for (var i = 2; i < tempclone.length; i++) {
                        var node = tempclone[i];
                        if (node[0] === 'text' && node[1]['s:attribute']) {
                            var attrib = node[1]['s:attribute'];
                            if (!(attrib in this.attributes)) {
                                node[2] = '';
                            }
                        }
                    }
                    tempclone[1].id = 'cell_' + this.key;
                    tempclone[1].transform = 'translate(' + cell.x + ',' + cell.y + ')';
                    if (this.type === '$_split_') {
                        setGenericSize(tempclone, Number(this.getGenericHeight()));
                        var outPorts_1 = Skin_1.default.getPortsWithPrefix(template, 'out');
                        var gap_1 = Number(outPorts_1[1][1]['s:y']) - Number(outPorts_1[0][1]['s:y']);
                        var startY_1 = Number(outPorts_1[0][1]['s:y']);
                        tempclone.pop();
                        tempclone.pop();
                        this.outputPorts.forEach(function (op, i) {
                            var portClone = clone(outPorts_1[0]);
                            portClone[portClone.length - 1][2] = op.Key;
                            portClone[1].transform = 'translate(' + outPorts_1[1][1]['s:x'] + ','
                                + (startY_1 + i * gap_1) + ')';
                            tempclone.push(portClone);
                        });
                    }
                    else if (this.type === '$_join_') {
                        setGenericSize(tempclone, Number(this.getGenericHeight()));
                        var inPorts_1 = Skin_1.default.getPortsWithPrefix(template, 'in');
                        var gap_2 = Number(inPorts_1[1][1]['s:y']) - Number(inPorts_1[0][1]['s:y']);
                        var startY_2 = Number(inPorts_1[0][1]['s:y']);
                        tempclone.pop();
                        tempclone.pop();
                        this.inputPorts.forEach(function (port, i) {
                            var portClone = clone(inPorts_1[0]);
                            portClone[portClone.length - 1][2] = port.Key;
                            portClone[1].transform = 'translate(' + inPorts_1[1][1]['s:x'] + ','
                                + (startY_2 + i * gap_2) + ')';
                            tempclone.push(portClone);
                        });
                    }
                    else if (template[1]['s:type'] === 'generic') {
                        setGenericSize(tempclone, Number(this.getGenericHeight()));
                        var inPorts_2 = Skin_1.default.getPortsWithPrefix(template, 'in');
                        var ingap_1 = Number(inPorts_2[1][1]['s:y']) - Number(inPorts_2[0][1]['s:y']);
                        var instartY_1 = Number(inPorts_2[0][1]['s:y']);
                        var outPorts_2 = Skin_1.default.getPortsWithPrefix(template, 'out');
                        var outgap_1 = Number(outPorts_2[1][1]['s:y']) - Number(outPorts_2[0][1]['s:y']);
                        var outstartY_1 = Number(outPorts_2[0][1]['s:y']);
                        tempclone.pop();
                        tempclone.pop();
                        tempclone.pop();
                        tempclone.pop();
                        this.inputPorts.forEach(function (port, i) {
                            var portClone = clone(inPorts_2[0]);
                            portClone[portClone.length - 1][2] = port.Key;
                            portClone[1].transform = 'translate(' + inPorts_2[1][1]['s:x'] + ','
                                + (instartY_1 + i * ingap_1) + ')';
                            portClone[1].id = 'port_' + port.parentNode.Key + '~' + port.Key;
                            tempclone.push(portClone);
                        });
                        this.outputPorts.forEach(function (port, i) {
                            var portClone = clone(outPorts_2[0]);
                            portClone[portClone.length - 1][2] = port.Key;
                            portClone[1].transform = 'translate(' + outPorts_2[1][1]['s:x'] + ','
                                + (outstartY_1 + i * outgap_1) + ')';
                            portClone[1].id = 'port_' + port.parentNode.Key + '~' + port.Key;
                            tempclone.push(portClone);
                        });
                        // first child of generic must be a text node.
                        tempclone[2][2] = this.type;
                    }
                    setClass(tempclone, '$cell_id', 'cell_' + this.key);
                    return tempclone;
                };
                Cell.prototype.addLabels = function (template, cell) {
                    var _this = this;
                    onml.traverse(template, {
                        enter: function (node) {
                            if (node.name === 'text' && node.attr['s:attribute']) {
                                var attrName = node.attr['s:attribute'];
                                var newString = void 0;
                                if (attrName === 'ref' || attrName === 'id') {
                                    if (_this.type === '$_constant_' && _this.key.length > 3) {
                                        var num = parseInt(_this.key, 2);
                                        newString = '0x' + num.toString(16);
                                    }
                                    else {
                                        newString = _this.key;
                                    }
                                    _this.attributes[attrName] = _this.key;
                                }
                                else if (attrName in _this.attributes) {
                                    newString = _this.attributes[attrName];
                                }
                                else {
                                    return;
                                }
                                cell.labels.push({
                                    id: _this.key + '.label.' + attrName,
                                    text: newString,
                                    x: node.attr.x,
                                    y: node.attr.y - 6,
                                    height: 11,
                                    width: (6 * newString.length),
                                });
                            }
                        },
                    });
                };
                Cell.prototype.getGenericHeight = function () {
                    var template = this.getTemplate();
                    var inPorts = Skin_1.default.getPortsWithPrefix(template, 'in');
                    var outPorts = Skin_1.default.getPortsWithPrefix(template, 'out');
                    if (this.inputPorts.length > this.outputPorts.length) {
                        var gap = Number(inPorts[1][1]['s:y']) - Number(inPorts[0][1]['s:y']);
                        return Number(template[1]['s:height']) + gap * (this.inputPorts.length - 2);
                    }
                    if (outPorts.length > 1) {
                        var gap = Number(outPorts[1][1]['s:y']) - Number(outPorts[0][1]['s:y']);
                        return Number(template[1]['s:height']) + gap * (this.outputPorts.length - 2);
                    }
                    return Number(template[1]['s:height']);
                };
                return Cell;
            }());
            exports.default = Cell;
            function setGenericSize(tempclone, height) {
                onml.traverse(tempclone, {
                    enter: function (node) {
                        if (node.name === 'rect' && node.attr['s:generic'] === 'body') {
                            node.attr.height = height;
                        }
                    },
                });
            }
            function setTextAttribute(tempclone, attribute, value) {
                onml.traverse(tempclone, {
                    enter: function (node) {
                        if (node.name === 'text' && node.attr['s:attribute'] === attribute) {
                            node.full[2] = value;
                        }
                    },
                });
            }
            function setClass(tempclone, searchKey, className) {
                onml.traverse(tempclone, {
                    enter: function (node) {
                        var currentClass = node.attr.class;
                        if (currentClass && currentClass.includes(searchKey)) {
                            node.attr.class = currentClass.replace(searchKey, className);
                        }
                    },
                });
            }
            function getBits(signals, indicesString) {
                var index = indicesString.indexOf(':');
                // is it the whole thing?
                if (index === -1) {
                    return [signals[Number(indicesString)]];
                }
                else {
                    var start = indicesString.slice(0, index);
                    var end = indicesString.slice(index + 1);
                    var slice = signals.slice(Number(start), Number(end) + 1);
                    return slice;
                }
            }

        }, { "./FlatModule": 27, "./Port": 28, "./Skin": 29, "./YosysModel": 30, "clone": 98, "lodash": 102, "onml": 104 }], 27: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.removeDups = exports.addToDefaultDict = exports.arrayToBitstring = exports.FlatModule = void 0;
            var Skin_1 = require("./Skin");
            var Cell_1 = require("./Cell");
            var _ = require("lodash");
            var FlatModule = /** @class */ (function () {
                function FlatModule(netlist) {
                    var _this = this;
                    this.moduleName = null;
                    _.forEach(netlist.modules, function (mod, name) {
                        if (mod.attributes && Number(mod.attributes.top) === 1) {
                            _this.moduleName = name;
                        }
                    });
                    // Otherwise default the first one in the file...
                    if (this.moduleName == null) {

                        this.moduleName = Object.keys(netlist.modules)[0];
                    }
                    var top = netlist.modules[this.moduleName];
                    var ports = _.map(top.ports, Cell_1.default.fromPort);
                    var cells = _.map(top.cells, function (c, key) { return Cell_1.default.fromYosysCell(c, key); });
                    this.nodes = cells.concat(ports);
                    // populated by createWires
                    this.wires = [];
                }
                // converts input ports with constant assignments to constant nodes
                FlatModule.prototype.addConstants = function () {
                    // find the maximum signal number
                    var maxNum = this.nodes.reduce((function (acc, v) { return v.maxOutVal(acc); }), -1);
                    // add constants to nodes
                    var signalsByConstantName = {};
                    var cells = [];
                    this.nodes.forEach(function (n) {
                        maxNum = n.findConstants(signalsByConstantName, maxNum, cells);
                    });
                    this.nodes = this.nodes.concat(cells);
                };
                // solves for minimal bus splits and joins and adds them to module
                FlatModule.prototype.addSplitsJoins = function () {
                    var allInputs = _.flatMap(this.nodes, function (n) { return n.inputPortVals(); });
                    var allOutputs = _.flatMap(this.nodes, function (n) { return n.outputPortVals(); });
                    var allInputsCopy = allInputs.slice();
                    var splits = {};
                    var joins = {};
                    allInputs.forEach(function (input) {
                        gather(allOutputs, allInputsCopy, input, 0, input.length, splits, joins);
                    });
                    this.nodes = this.nodes.concat(_.map(joins, function (joinOutput, joinInputs) {
                        return Cell_1.default.fromJoinInfo(joinInputs, joinOutput);
                    })).concat(_.map(splits, function (splitOutputs, splitInput) {
                        return Cell_1.default.fromSplitInfo(splitInput, splitOutputs);
                    }));
                };
                // search through all the ports to find all of the wires
                FlatModule.prototype.createWires = function () {
                    var layoutProps = Skin_1.default.getProperties();
                    var ridersByNet = {};
                    var driversByNet = {};
                    var lateralsByNet = {};
                    this.nodes.forEach(function (n) {
                        n.collectPortsByDirection(ridersByNet, driversByNet, lateralsByNet, layoutProps.genericsLaterals);
                    });
                    // list of unique nets
                    var nets = removeDups(_.keys(ridersByNet).concat(_.keys(driversByNet)).concat(_.keys(lateralsByNet)));
                    var wires = nets.map(function (net) {
                        var drivers = driversByNet[net] || [];
                        var riders = ridersByNet[net] || [];
                        var laterals = lateralsByNet[net] || [];
                        var wire = { netName: net, drivers: drivers, riders: riders, laterals: laterals };
                        drivers.concat(riders).concat(laterals).forEach(function (port) {
                            port.wire = wire;
                        });
                        return wire;
                    });
                    this.wires = wires;
                };
                return FlatModule;
            }());
            exports.FlatModule = FlatModule;
            // returns a string that represents the values of the array of integers
            // [1, 2, 3] -> ',1,2,3,'
            function arrayToBitstring(bitArray) {
                var ret = '';
                bitArray.forEach(function (bit) {
                    var sbit = String(bit);
                    if (ret === '') {
                        ret = sbit;
                    }
                    else {
                        ret += ',' + sbit;
                    }
                });
                return ',' + ret + ',';
            }
            exports.arrayToBitstring = arrayToBitstring;
            // returns whether needle is a substring of haystack
            function arrayContains(needle, haystack) {
                return (haystack.indexOf(needle) > -1);
            }
            // returns the index of the string that contains a substring
            // given arrhaystack, an array of strings
            function indexOfContains(needle, arrhaystack) {
                return _.findIndex(arrhaystack, function (haystack) {
                    return arrayContains(needle, haystack);
                });
            }
            function addToDefaultDict(dict, key, value) {
                if (dict[key] === undefined) {
                    dict[key] = [value];
                }
                else {
                    dict[key].push(value);
                }
            }
            exports.addToDefaultDict = addToDefaultDict;
            // string (for labels), that represents an index
            // or range of indices.
            function getIndicesString(bitstring, query, start) {
                var splitStart = _.max([bitstring.indexOf(query), start]);
                var startIndex = bitstring.substring(0, splitStart).split(',').length - 1;
                var endIndex = startIndex + query.split(',').length - 3;
                if (startIndex === endIndex) {
                    return String(startIndex);
                }
                else {
                    return String(startIndex) + ':' + String(endIndex);
                }
            }
            // gather splits and joins
            function gather(inputs, // all inputs
                outputs, // all outputs
                toSolve, // an input array we are trying to solve
                start, // index of toSolve to start from
                end, // index of toSolve to end at
                splits, // container collecting the splits
                joins) {
                // remove myself from outputs list if present
                var outputIndex = outputs.indexOf(toSolve);
                if (outputIndex !== -1) {
                    outputs.splice(outputIndex, 1);
                }
                // This toSolve is compconste
                if (start >= toSolve.length || end - start < 2) {
                    return;
                }
                var query = toSolve.slice(start, end);
                // are there are perfect matches?
                if (arrayContains(query, inputs)) {
                    if (query !== toSolve) {
                        addToDefaultDict(joins, toSolve, getIndicesString(toSolve, query, start));
                    }
                    gather(inputs, outputs, toSolve, end - 1, toSolve.length, splits, joins);
                    return;
                }
                var index = indexOfContains(query, inputs);
                // are there any partial matches?
                if (index !== -1) {
                    if (query !== toSolve) {
                        addToDefaultDict(joins, toSolve, getIndicesString(toSolve, query, start));
                    }
                    // found a split
                    addToDefaultDict(splits, inputs[index], getIndicesString(inputs[index], query, 0));
                    // we can match to this now
                    inputs.push(query);
                    gather(inputs, outputs, toSolve, end - 1, toSolve.length, splits, joins);
                    return;
                }
                // are there any output matches?
                if (indexOfContains(query, outputs) !== -1) {
                    if (query !== toSolve) {
                        // add to join
                        addToDefaultDict(joins, toSolve, getIndicesString(toSolve, query, start));
                    }
                    // gather without outputs
                    gather(inputs, [], query, 0, query.length, splits, joins);
                    inputs.push(query);
                    return;
                }
                gather(inputs, outputs, toSolve, start, start + query.slice(0, -1).lastIndexOf(',') + 1, splits, joins);
            }
            function removeDups(inStrs) {
                var map = {};
                inStrs.forEach(function (str) {
                    map[str] = true;
                });
                return _.keys(map);
            }
            exports.removeDups = removeDups;

        }, { "./Cell": 26, "./Skin": 29, "lodash": 102 }], 28: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.Port = void 0;
            var Cell_1 = require("./Cell");
            var _ = require("lodash");
            var Port = /** @class */ (function () {
                function Port(key, value) {
                    this.key = key;
                    this.value = value;
                }
                Object.defineProperty(Port.prototype, "Key", {
                    get: function () {
                        return this.key;
                    },
                    enumerable: false,
                    configurable: true
                });
                Port.prototype.keyIn = function (pids) {
                    return _.includes(pids, this.key);
                };
                Port.prototype.maxVal = function () {
                    return _.max(_.map(this.value, function (v) { return Number(v); }));
                };
                Port.prototype.valString = function () {
                    return ',' + this.value.join() + ',';
                };
                Port.prototype.findConstants = function (sigsByConstantName, maxNum, constantCollector) {
                    var _this = this;
                    var constNameCollector = '';
                    var constNumCollector = [];
                    var portSigs = this.value;
                    portSigs.forEach(function (portSig, portSigIndex) {
                        // is constant?
                        if (portSig === '0' || portSig === '1') {
                            maxNum += 1;
                            constNameCollector += portSig;
                            // replace the constant with new signal num
                            portSigs[portSigIndex] = maxNum;
                            constNumCollector.push(maxNum);
                            // string of constants ended before end of p.value
                        }
                        else if (constNumCollector.length > 0) {
                            _this.assignConstant(constNameCollector, constNumCollector, portSigIndex, sigsByConstantName, constantCollector);
                            // reset name and num collectors
                            constNameCollector = '';
                            constNumCollector = [];
                        }
                    });
                    if (constNumCollector.length > 0) {
                        this.assignConstant(constNameCollector, constNumCollector, portSigs.length, sigsByConstantName, constantCollector);
                    }
                    return maxNum;
                };
                Port.prototype.getGenericElkPort = function (index, templatePorts, dir) {
                    var nkey = this.parentNode.Key;
                    var type = this.parentNode.getTemplate()[1]['s:type'];
                    if (index === 0) {
                        var ret = {
                            id: nkey + '.' + this.key,
                            width: 1,
                            height: 1,
                            x: Number(templatePorts[0][1]['s:x']),
                            y: Number(templatePorts[0][1]['s:y']),
                        };
                        if ((type === 'generic' || type === 'join') && dir === 'in') {
                            ret.labels = [{
                                id: nkey + '.' + this.key + '.label',
                                text: this.key,
                                x: Number(templatePorts[0][2][1].x) - 10,
                                y: Number(templatePorts[0][2][1].y) - 6,
                                width: (6 * this.key.length),
                                height: 11,
                            }];
                        }
                        if ((type === 'generic' || type === 'split') && dir === 'out') {
                            ret.labels = [{
                                id: nkey + '.' + this.key + '.label',
                                text: this.key,
                                x: Number(templatePorts[0][2][1].x) - 10,
                                y: Number(templatePorts[0][2][1].y) - 6,
                                width: (6 * this.key.length),
                                height: 11,
                            }];
                        }
                        return ret;
                    }
                    else {
                        var gap = Number(templatePorts[1][1]['s:y']) - Number(templatePorts[0][1]['s:y']);
                        var ret = {
                            id: nkey + '.' + this.key,
                            width: 1,
                            height: 1,
                            x: Number(templatePorts[0][1]['s:x']),
                            y: (index) * gap + Number(templatePorts[0][1]['s:y']),
                        };
                        if (type === 'generic') {
                            ret.labels = [{
                                id: nkey + '.' + this.key + '.label',
                                text: this.key,
                                x: Number(templatePorts[0][2][1].x) - 10,
                                y: Number(templatePorts[0][2][1].y) - 6,
                                width: (6 * this.key.length),
                                height: 11,
                            }];
                        }
                        return ret;
                    }
                };
                Port.prototype.assignConstant = function (nameCollector, constants, currIndex, signalsByConstantName, constantCollector) {
                    var _this = this;
                    // we've been appending to nameCollector, so reverse to get const name
                    var constName = nameCollector.split('').reverse().join('');
                    // if the constant has already been used
                    if (signalsByConstantName.hasOwnProperty(constName)) {
                        var constSigs = signalsByConstantName[constName];
                        // go back and fix signal values
                        var constLength_1 = constSigs.length;
                        constSigs.forEach(function (constSig, constIndex) {
                            // i is where in port_signals we need to update
                            var i = currIndex - constLength_1 + constIndex;
                            _this.value[i] = constSig;
                        });
                    }
                    else {
                        constantCollector.push(Cell_1.default.fromConstantInfo(constName, constants));
                        signalsByConstantName[constName] = constants;
                    }
                };
                return Port;
            }());
            exports.Port = Port;

        }, { "./Cell": 26, "lodash": 102 }], 29: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.Skin = void 0;
            var onml = require("onml");
            var _ = require("lodash");
            var Skin;
            (function (Skin) {
                Skin.skin = null;
                function getPortsWithPrefix(template, prefix) {
                    var ports = _.filter(template, function (e) {
                        try {
                            if (e instanceof Array && e[0] === 'g') {
                                return e[1]['s:pid'].startsWith(prefix);
                            }
                        }
                        catch (exception) {
                            // Do nothing if the SVG group doesn't have a pin id.
                        }
                    });
                    return ports;
                }
                Skin.getPortsWithPrefix = getPortsWithPrefix;
                function filterPortPids(template, filter) {
                    var ports = _.filter(template, function (element) {
                        var tag = element[0];
                        if (element instanceof Array && tag === 'g') {
                            var attrs = element[1];
                            return filter(attrs);
                        }
                        return false;
                    });
                    return ports.map(function (port) {
                        return port[1]['s:pid'];
                    });
                }
                function getInputPids(template) {
                    return filterPortPids(template, function (attrs) {
                        if (attrs['s:position']) {
                            return attrs['s:position'] === 'top';
                        }
                        return false;
                    });
                }
                Skin.getInputPids = getInputPids;
                function getOutputPids(template) {
                    return filterPortPids(template, function (attrs) {
                        if (attrs['s:position']) {
                            return attrs['s:position'] === 'bottom';
                        }
                        return false;
                    });
                }
                Skin.getOutputPids = getOutputPids;
                function getLateralPortPids(template) {
                    return filterPortPids(template, function (attrs) {
                        if (attrs['s:dir']) {
                            return attrs['s:dir'] === 'lateral';
                        }
                        if (attrs['s:position']) {
                            return attrs['s:position'] === 'left' ||
                                attrs['s:position'] === 'right';
                        }
                        return false;
                    });
                }
                Skin.getLateralPortPids = getLateralPortPids;
                function findSkinType(type) {
                    var ret = null;
                    onml.traverse(Skin.skin, {
                        enter: function (node, parent) {
                            if (node.name === 's:alias' && node.attr.val === type) {
                                ret = parent;
                            }
                        },
                    });
                    if (ret == null) {
                        onml.traverse(Skin.skin, {
                            enter: function (node) {
                                if (node.attr['s:type'] === 'generic') {
                                    ret = node;
                                }
                            },
                        });
                    }
                    return ret.full;
                }
                Skin.findSkinType = findSkinType;
                function getLowPriorityAliases() {
                    var ret = [];
                    onml.t(Skin.skin, {
                        enter: function (node) {
                            if (node.name === 's:low_priority_alias') {
                                ret.push(node.attr.value);
                            }
                        },
                    });
                    return ret;
                }
                Skin.getLowPriorityAliases = getLowPriorityAliases;
                function getProperties() {
                    var vals;
                    onml.t(Skin.skin, {
                        enter: function (node) {
                            if (node.name === 's:properties') {
                                vals = _.mapValues(node.attr, function (val) {
                                    if (!isNaN(Number(val))) {
                                        return Number(val);
                                    }
                                    if (val === 'true') {
                                        return true;
                                    }
                                    if (val === 'false') {
                                        return false;
                                    }
                                    return val;
                                });
                            }
                            else if (node.name === 's:layoutEngine') {
                                vals.layoutEngine = node.attr;
                            }
                        },
                    });
                    if (!vals.layoutEngine) {
                        vals.layoutEngine = {};
                    }
                    return vals;
                }
                Skin.getProperties = getProperties;
            })(Skin = exports.Skin || (exports.Skin = {}));
            exports.default = Skin;

        }, { "lodash": 102, "onml": 104 }], 30: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            var Yosys;
            (function (Yosys) {
                var ConstantVal;
                (function (ConstantVal) {
                    ConstantVal["Zero"] = "0";
                    ConstantVal["One"] = "1";
                    ConstantVal["X"] = "x";
                })(ConstantVal || (ConstantVal = {}));
                var Direction;
                (function (Direction) {
                    Direction["Input"] = "input";
                    Direction["Output"] = "output";
                })(Direction = Yosys.Direction || (Yosys.Direction = {}));
                function getInputPortPids(cell) {
                    if (cell.port_directions) {
                        return Object.keys(cell.port_directions).filter(function (k) {
                            return cell.port_directions[k] === Direction.Input;
                        });
                    }
                    return [];
                }
                Yosys.getInputPortPids = getInputPortPids;
                function getOutputPortPids(cell) {
                    if (cell.port_directions) {
                        return Object.keys(cell.port_directions).filter(function (k) {
                            return cell.port_directions[k] === Direction.Output;
                        });
                    }
                    return [];
                }
                Yosys.getOutputPortPids = getOutputPortPids;
                var HideName;
                (function (HideName) {
                    HideName[HideName["Hide"] = 0] = "Hide";
                    HideName[HideName["NoHide"] = 1] = "NoHide";
                })(HideName || (HideName = {}));
            })(Yosys || (Yosys = {}));
            exports.default = Yosys;

        }, {}], 31: [function (require, module, exports) {
            "use strict";
            var __spreadArrays = (this && this.__spreadArrays) || function () {
                for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
                for (var r = Array(s), k = 0, i = 0; i < il; i++)
                    for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
                        r[k] = a[j];
                return r;
            };
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.removeDummyEdges = void 0;
            var elkGraph_1 = require("./elkGraph");
            var Skin_1 = require("./Skin");
            var _ = require("lodash");
            var onml = require("onml");
            var WireDirection;
            (function (WireDirection) {
                WireDirection[WireDirection["Up"] = 0] = "Up";
                WireDirection[WireDirection["Down"] = 1] = "Down";
                WireDirection[WireDirection["Left"] = 2] = "Left";
                WireDirection[WireDirection["Right"] = 3] = "Right";
            })(WireDirection || (WireDirection = {}));
            function drawModule(g, module) {
                var nodes = module.nodes.map(function (n) {
                    var kchild = _.find(g.children, function (c) { return c.id === n.Key; });
                    return n.render(kchild);
                });
                removeDummyEdges(g);
                var lines = _.flatMap(g.edges, function (e) {
                    var netId = elkGraph_1.ElkModel.wireNameLookup[e.id];
                    var numWires = netId.split(',').length - 2;
                    var lineStyle = 'stroke-width: ' + (numWires > 1 ? 2 : 1);
                    var netName = 'net_' + netId.slice(1, netId.length - 1) + ' width_' + numWires;
                    return _.flatMap(e.sections, function (s) {
                        var startPoint = s.startPoint;
                        s.bendPoints = s.bendPoints || [];
                        var bends = s.bendPoints.map(function (b) {
                            var l = ['line', {
                                x1: startPoint.x,
                                x2: b.x,
                                y1: startPoint.y,
                                y2: b.y,
                                class: netName,
                                style: lineStyle,
                            }];
                            startPoint = b;
                            return l;
                        });
                        if (e.junctionPoints) {
                            var circles = e.junctionPoints.map(function (j) {
                                return ['circle', {
                                    cx: j.x,
                                    cy: j.y,
                                    r: (numWires > 1 ? 3 : 2),
                                    style: 'fill:#000',
                                    class: netName,
                                }];
                            });
                            bends = bends.concat(circles);
                        }
                        var line = [['line', {
                            x1: startPoint.x,
                            x2: s.endPoint.x,
                            y1: startPoint.y,
                            y2: s.endPoint.y,
                            class: netName,
                            style: lineStyle,
                        }]];
                        return bends.concat(line);
                    });
                });
                var labels;
                for (var index in g.edges) {
                    if (g.edges.hasOwnProperty(index)) {
                        var e = g.edges[index];
                        var netId = elkGraph_1.ElkModel.wireNameLookup[e.id];
                        var numWires = netId.split(',').length - 2;
                        var netName = 'net_' + netId.slice(1, netId.length - 1) +
                            ' width_' + numWires +
                            ' busLabel_' + numWires;
                        if (e.labels !== undefined &&
                            e.labels[0] !== undefined &&
                            e.labels[0].text !== undefined) {
                            var label = [
                                ['rect',
                                    {
                                        x: e.labels[0].x + 1,
                                        y: e.labels[0].y - 1,
                                        width: (e.labels[0].text.length + 2) * 6 - 2,
                                        height: 9,
                                        class: netName,
                                        style: 'fill: white; stroke: none',
                                    },
                                ], ['text',
                                    {
                                        x: e.labels[0].x,
                                        y: e.labels[0].y + 7,
                                        class: netName,
                                    },
                                    '/' + e.labels[0].text + '/',
                                ],
                            ];
                            if (labels !== undefined) {
                                labels = labels.concat(label);
                            }
                            else {
                                labels = label;
                            }
                        }
                    }
                }
                if (labels !== undefined && labels.length > 0) {
                    lines = lines.concat(labels);
                }
                var svgAttrs = Skin_1.default.skin[1];
                svgAttrs.width = g.width.toString();
                svgAttrs.height = g.height.toString();
                var styles = ['style', {}, ''];
                onml.t(Skin_1.default.skin, {
                    enter: function (node) {
                        if (node.name === 'style') {
                            styles[2] += node.full[2];
                        }
                    },
                });
                var elements = __spreadArrays([styles], nodes, lines);
                var ret = __spreadArrays(['svg', svgAttrs], elements);
                return onml.s(ret);
            }
            exports.default = drawModule;
            function which_dir(start, end) {
                if (end.x === start.x && end.y === start.y) {
                    throw new Error('start and end are the same');
                }
                if (end.x !== start.x && end.y !== start.y) {
                    throw new Error('start and end arent orthogonal');
                }
                if (end.x > start.x) {
                    return WireDirection.Right;
                }
                if (end.x < start.x) {
                    return WireDirection.Left;
                }
                if (end.y > start.y) {
                    return WireDirection.Down;
                }
                if (end.y < start.y) {
                    return WireDirection.Up;
                }
                throw new Error('unexpected direction');
            }
            function findBendNearDummy(net, dummyIsSource, dummyLoc) {
                var candidates = net.map(function (edge) {
                    var bends = edge.sections[0].bendPoints || [null];
                    if (dummyIsSource) {
                        return _.first(bends);
                    }
                    else {
                        return _.last(bends);
                    }
                }).filter(function (p) { return p !== null; });
                return _.minBy(candidates, function (pt) {
                    return Math.abs(dummyLoc.x - pt.x) + Math.abs(dummyLoc.y - pt.y);
                });
            }
            function removeDummyEdges(g) {
                // go through each edge group for each dummy
                var dummyNum = 0;
                var _loop_1 = function () {
                    var dummyId = '$d_' + String(dummyNum);
                    // find all edges connected to this dummy
                    var edgeGroup = _.filter(g.edges, function (e) {
                        return e.source === dummyId || e.target === dummyId;
                    });
                    if (edgeGroup.length === 0) {
                        return "break";
                    }
                    var dummyIsSource;
                    var dummyLoc = void 0;
                    var firstEdge = edgeGroup[0];
                    if (firstEdge.source === dummyId) {
                        dummyIsSource = true;
                        dummyLoc = firstEdge.sections[0].startPoint;
                    }
                    else {
                        dummyIsSource = false;
                        dummyLoc = firstEdge.sections[0].endPoint;
                    }
                    var newEnd = findBendNearDummy(edgeGroup, dummyIsSource, dummyLoc);
                    for (var _i = 0, edgeGroup_1 = edgeGroup; _i < edgeGroup_1.length; _i++) {
                        var edge = edgeGroup_1[_i];
                        var e = edge;
                        var section = e.sections[0];
                        if (dummyIsSource) {
                            section.startPoint = newEnd;
                            if (section.bendPoints) {
                                section.bendPoints.shift();
                            }
                        }
                        else {
                            section.endPoint = newEnd;
                            if (section.bendPoints) {
                                section.bendPoints.pop();
                            }
                        }
                    }
                    // delete junction point if necessary
                    var directions = new Set(_.flatMap(edgeGroup, function (edge) {
                        var section = edge.sections[0];
                        if (dummyIsSource) {
                            // get first bend or endPoint
                            if (section.bendPoints && section.bendPoints.length > 0) {
                                return [section.bendPoints[0]];
                            }
                            return section.endPoint;
                        }
                        else {
                            if (section.bendPoints && section.bendPoints.length > 0) {
                                return [_.last(section.bendPoints)];
                            }
                            return section.startPoint;
                        }
                    }).map(function (pt) {
                        if (pt.x > newEnd.x) {
                            return WireDirection.Right;
                        }
                        if (pt.x < newEnd.x) {
                            return WireDirection.Left;
                        }
                        if (pt.y > newEnd.y) {
                            return WireDirection.Down;
                        }
                        return WireDirection.Up;
                    }));
                    if (directions.size < 3) {
                        // remove junctions at newEnd
                        edgeGroup.forEach(function (edge) {
                            if (edge.junctionPoints) {
                                edge.junctionPoints = edge.junctionPoints.filter(function (junct) {
                                    return !_.isEqual(junct, newEnd);
                                });
                            }
                        });
                    }
                    dummyNum += 1;
                };
                // loop until we can't find an edge group or we hit 10,000
                while (dummyNum < 10000) {
                    var state_1 = _loop_1();
                    if (state_1 === "break")
                        break;
                }
            }
            exports.removeDummyEdges = removeDummyEdges;

        }, { "./Skin": 29, "./elkGraph": 32, "lodash": 102, "onml": 104 }], 32: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.buildElkGraph = exports.ElkModel = void 0;
            var _ = require("lodash");
            var ElkModel;
            (function (ElkModel) {
                ElkModel.wireNameLookup = {};
                ElkModel.dummyNum = 0;
                ElkModel.edgeIndex = 0;
            })(ElkModel = exports.ElkModel || (exports.ElkModel = {}));
            function buildElkGraph(module) {
                var children = module.nodes.map(function (n) {
                    return n.buildElkChild();
                });
                ElkModel.edgeIndex = 0;
                ElkModel.dummyNum = 0;
                var edges = _.flatMap(module.wires, function (w) {
                    var numWires = w.netName.split(',').length - 2;
                    // at least one driver and at least one rider and no laterals
                    if (w.drivers.length > 0 && w.riders.length > 0 && w.laterals.length === 0) {
                        var ret = [];
                        route(w.drivers, w.riders, ret, numWires);
                        return ret;
                        // at least one driver or rider and at least one lateral
                    }
                    else if (w.drivers.concat(w.riders).length > 0 && w.laterals.length > 0) {
                        var ret = [];
                        route(w.drivers, w.laterals, ret, numWires);
                        route(w.laterals, w.riders, ret, numWires);
                        return ret;
                        // at least two drivers and no riders
                    }
                    else if (w.riders.length === 0 && w.drivers.length > 1) {
                        // create a dummy node and add it to children
                        var dummyId_1 = addDummy(children);
                        ElkModel.dummyNum += 1;
                        var dummyEdges = w.drivers.map(function (driver) {
                            var sourceParentKey = driver.parentNode.Key;
                            var id = 'e' + String(ElkModel.edgeIndex);
                            ElkModel.edgeIndex += 1;
                            var d = {
                                id: id,
                                source: sourceParentKey,
                                sourcePort: sourceParentKey + '.' + driver.key,
                                target: dummyId_1,
                                targetPort: dummyId_1 + '.p',
                            };
                            ElkModel.wireNameLookup[id] = driver.wire.netName;
                            return d;
                        });
                        return dummyEdges;
                        // at least one rider and no drivers
                    }
                    else if (w.riders.length > 1 && w.drivers.length === 0) {
                        // create a dummy node and add it to children
                        var dummyId_2 = addDummy(children);
                        ElkModel.dummyNum += 1;
                        var dummyEdges = w.riders.map(function (rider) {
                            var sourceParentKey = rider.parentNode.Key;
                            var id = 'e' + String(ElkModel.edgeIndex);
                            ElkModel.edgeIndex += 1;
                            var edge = {
                                id: id,
                                source: dummyId_2,
                                sourcePort: dummyId_2 + '.p',
                                target: sourceParentKey,
                                targetPort: sourceParentKey + '.' + rider.key,
                            };
                            ElkModel.wireNameLookup[id] = rider.wire.netName;
                            return edge;
                        });
                        return dummyEdges;
                    }
                    else if (w.laterals.length > 1) {
                        var source_1 = w.laterals[0];
                        var sourceParentKey_1 = source_1.parentNode.Key;
                        var lateralEdges = w.laterals.slice(1).map(function (lateral) {
                            var lateralParentKey = lateral.parentNode.Key;
                            var id = 'e' + String(ElkModel.edgeIndex);
                            ElkModel.edgeIndex += 1;
                            var edge = {
                                id: id,
                                source: sourceParentKey_1,
                                sourcePort: sourceParentKey_1 + '.' + source_1.key,
                                target: lateralParentKey,
                                targetPort: lateralParentKey + '.' + lateral.key,
                            };
                            ElkModel.wireNameLookup[id] = lateral.wire.netName;
                            return edge;
                        });
                        return lateralEdges;
                    }
                    // for only one driver or only one rider, don't create any edges
                    return [];
                });
                return {
                    id: module.moduleName,
                    children: children,
                    edges: edges,
                };
            }
            exports.buildElkGraph = buildElkGraph;
            function addDummy(children) {
                var dummyId = '$d_' + String(ElkModel.dummyNum);
                var child = {
                    id: dummyId,
                    width: 0,
                    height: 0,
                    ports: [{
                        id: dummyId + '.p',
                        width: 0,
                        height: 0,
                    }],
                    layoutOptions: { 'org.eclipse.elk.portConstraints': 'FIXED_SIDE' },
                };
                children.push(child);
                return dummyId;
            }
            function route(sourcePorts, targetPorts, edges, numWires) {
                var newEdges = (_.flatMap(sourcePorts, function (sourcePort) {
                    var sourceParentKey = sourcePort.parentNode.key;
                    var sourceKey = sourceParentKey + '.' + sourcePort.key;
                    var edgeLabel;
                    if (numWires > 1) {
                        edgeLabel = [{
                            id: '',
                            text: String(numWires),
                            width: 4,
                            height: 6,
                            x: 0,
                            y: 0,
                            layoutOptions: {
                                'org.eclipse.elk.edgeLabels.inline': true,
                            },
                        }];
                    }
                    return targetPorts.map(function (targetPort) {
                        var targetParentKey = targetPort.parentNode.key;
                        var targetKey = targetParentKey + '.' + targetPort.key;
                        var id = 'e' + ElkModel.edgeIndex;
                        var edge = {
                            id: id,
                            labels: edgeLabel,
                            sources: [sourceKey],
                            targets: [targetKey],
                        };
                        ElkModel.wireNameLookup[id] = targetPort.wire.netName;
                        if (sourcePort.parentNode.type !== '$dff') {
                            edge.layoutOptions = {
                                'org.eclipse.elk.layered.priority.direction': 10,
                                'org.eclipse.elk.edge.thickness': (numWires > 1 ? 2 : 1)
                            };
                        }
                        else {
                            edge.layoutOptions = { 'org.eclipse.elk.edge.thickness': (numWires > 1 ? 2 : 1) };
                        }
                        ElkModel.edgeIndex += 1;
                        return edge;
                    });
                }));
                edges.push.apply(edges, newEdges);
            }

        }, { "lodash": 102 }], 33: [function (require, module, exports) {
            (function (global) {
                (function () {
                    'use strict';
                    Object.defineProperty(exports, "__esModule", { value: true });
                    exports.render = exports.dumpLayout = void 0;
                    var ELK = (typeof window !== "undefined" ? window['ELK'] : typeof global !== "undefined" ? global['ELK'] : null);
                    var onml = require("onml");
                    var FlatModule_1 = require("./FlatModule");
                    var Skin_1 = require("./Skin");
                    var elkGraph_1 = require("./elkGraph");
                    var drawModule_1 = require("./drawModule");
                    var elk = new ELK();

                    function createFlatModule(skinData, yosysNetlist) {
                        Skin_1.default.skin = onml.p(skinData);
                        var layoutProps = Skin_1.default.getProperties();
                        var flatModule = new FlatModule_1.FlatModule(yosysNetlist);
                        // this can be skipped if there are no 0's or 1's
                        if (layoutProps.constants !== false) {
                            flatModule.addConstants();
                        }
                        // this can be skipped if there are no splits or joins
                        if (layoutProps.splitsAndJoins !== false) {
                            flatModule.addSplitsJoins();
                        }
                        flatModule.createWires();
                        return flatModule;
                    }
                    exports.createFlatModule = createFlatModule;

                    function dumpLayout(skinData, yosysNetlist, prelayout, done) {
                        var flatModule = createFlatModule(skinData, yosysNetlist);
                        var kgraph = elkGraph_1.buildElkGraph(flatModule);
                        if (prelayout) {
                            done(null, JSON.stringify(kgraph, null, 2));
                            return;
                        }
                        var layoutProps = Skin_1.default.getProperties();
                        var promise = elk.layout(kgraph, { layoutOptions: layoutProps.layoutEngine });
                        promise.then(function (graph) {
                            done(null, JSON.stringify(graph, null, 2));
                        }).catch(function (reason) {
                            throw Error(reason);
                        });
                    }
                    exports.dumpLayout = dumpLayout;

                    function render(skinData, yosysNetlist, done, elkData) {
                        var flatModule = createFlatModule(skinData, yosysNetlist);
                        var kgraph = elkGraph_1.buildElkGraph(flatModule);
                        var layoutProps = Skin_1.default.getProperties();
                        var promise;
                        // if we already have a layout then use it
                        if (elkData) {
                            promise = new Promise(function (resolve) {
                                drawModule_1.default(elkData, flatModule);
                                resolve();
                            });
                        }
                        else {
                            // otherwise use ELK to generate the layout
                            promise = elk.layout(kgraph, { layoutOptions: layoutProps.layoutEngine })
                                .then(function (g) { return drawModule_1.default(g, flatModule); })
                                // tslint:disable-next-line:no-console
                                .catch(function (e) { console.error(e); });
                        }
                        // support legacy callback style
                        if (typeof done === 'function') {
                            promise.then(function (output) {
                                done(null, output);
                                return output;
                            }).catch(function (reason) {
                                throw Error(reason);
                            });
                        }
                        return promise;
                    }
                    exports.render = render;

                }).call(this)
            }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
        }, { "./FlatModule": 27, "./Skin": 29, "./drawModule": 31, "./elkGraph": 32, "onml": 104 }], 34: [function (require, module, exports) {
            (function (Buffer) {
                (function () {
                    const lib = require('../built');

                    const json5 = require('json5');
                    const Ajv = require('ajv');
                    var ajv = new Ajv({ allErrors: true });
                    require('ajv-errors')(ajv);

                    const schema = Buffer(" ", "base64");
                    const analog = "<svg xmlns=\"http://www.w3.org/2000/svg\"\n     xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n     xmlns:s=\"https://github.com/nturley/netlistsvg\">\n  <s:properties\n    constants=\"false\"\n    splitsAndJoins=\"false\"\n    genericsLaterals=\"true\">\n    <s:layoutEngine\n        org.eclipse.elk.layered.spacing.nodeNodeBetweenLayers=\"5\"\n        org.eclipse.elk.layered.compaction.postCompaction.strategy=\"4\"\n        org.eclipse.elk.spacing.nodeNode= \"35\"\n        org.eclipse.elk.direction=\"DOWN\"/>\n  </s:properties>\n<style>\nsvg {\n  stroke: #000;\n  fill: none;\n}\ntext {\n  fill: #000;\n  stroke: none;\n  font-size: 10px;\n  font-weight: bold;\n  font-family: \"Courier New\", monospace;\n}\n.nodelabel {\n  text-anchor: middle;\n}\n.inputPortLabel {\n  text-anchor: end;\n}\n.splitjoinBody {\n  fill: #000;\n}\n.symbol {\n  stroke-linejoin: round;\n  stroke-linecap: round;\n  stroke-width: 2;\n}\n.detail {\n  stroke-linejoin: round;\n  stroke-linecap: round;\n  fill: #000;\n}\n</style>\n\n<!-- power -->\n<g s:type=\"vcc\" s:width=\"20\" s:height=\"30\" transform=\"translate(5,20)\">\n  <s:alias val=\"vcc\" />\n  <text x=\"10\" y=\"-4\" class=\"nodelabel $cell_id\" s:attribute=\"name\">name</text>\n  <path d=\"M0,0 H20 L10,15 Z M10,15 V30\" class=\"$cell_id\"/>\n  <g s:x=\"10\" s:y=\"30\" s:pid=\"A\" s:position=\"bottom\"/>\n</g>\n\n<g s:type=\"vee\" s:width=\"20\" s:height=\"30\" transform=\"translate(40,35)\">\n\t  <s:alias val=\"vee\" />\n\t  <text x=\"10\" y=\"10\" class=\"nodelabel $cell_id\" s:attribute=\"name\">name</text>\n\t  <path d=\"M0,0 H20 L10,-15 Z M10,-15 V-30\" class=\"$cell_id\"/>\n\t  <g s:x=\"10\" s:y=\"-30\" s:pid=\"A\" s:position=\"top\"/>\n\t</g>\n\n<g s:type=\"gnd\" s:width=\"20\" s:height=\"30\" transform=\"translate(80,35)\">\n  <s:alias val=\"gnd\"/>\n  <text x=\"30\" y=\"20\" class=\"nodelabel $cell_id\" s:attribute=\"name\">name</text>\n  <path d=\"M0,0 H20 M3,5 H17 M7,10 H13 M10,0 V-15\" class=\"$cell_id\"/>\n  <g s:x=\"10\" s:y=\"-15\" s:pid=\"A\" s:position=\"top\"/>\n</g>\n<!-- power -->\n\n<!-- signal -->\n<g s:type=\"inputExt\" s:width=\"30\" s:height=\"20\" transform=\"translate(5,70)\">\n  <text x=\"15\" y=\"-4\" class=\"$cell_id\" s:attribute=\"ref\">input</text>\n  <s:alias val=\"$_inputExt_\"/>\n  <path d=\"M0,0 V20 H15 L30,10 15,0 Z\" class=\"$cell_id\"/>\n  <g s:x=\"30\" s:y=\"10\" s:pid=\"Y\" s:position=\"right\"/>\n</g>\n\n<g s:type=\"outputExt\" s:width=\"30\" s:height=\"20\" transform=\"translate(60,70)\">\n  <text x=\"15\" y=\"-4\" class=\"$cell_id\" s:attribute=\"ref\">output</text>\n  <s:alias val=\"$_outputExt_\"/>\n  <path d=\"M30,0 V20 H15 L0,10 15,0 Z\" class=\"$cell_id\"/>\n  <g s:x=\"0\" s:y=\"10\" s:pid=\"A\" s:position=\"left\"/>\n</g>\n<!-- signal -->\n\n<!-- passives -->\n<g s:type=\"resistor_h\" s:width=\"50\" s:height=\"10\" transform=\"translate(5,110)\">\n  <s:alias val=\"r_h\"/>\n  <text class=\"nodelabel $cell_id\" x=\"25\" y=\"-5\" s:attribute=\"ref\">X1</text>\n  <text class=\"nodelabel $cell_id\" x=\"25\" y=\"20\" s:attribute=\"value\">Xk</text>\n  <path d=\"M10,0 H40 V10 H10 Z\" class=\"symbol $cell_id\"/>\n  <path d=\"M0,5 H10 M40,5 H50\" class=\"connect $cell_id\"/>\n  <g s:x=\"0\" s:y=\"5\" s:pid=\"A\" s:position=\"left\"/>\n  <g s:x=\"50\" s:y=\"5\" s:pid=\"B\" s:position=\"right\"/>\n</g>\n\n<g s:type=\"resistor_v\" s:width=\"10\" s:height=\"50\" transform=\"translate(25,130)\">\n  <s:alias val=\"r_v\"/>\n  <text x=\"15\"  y=\"15\" s:attribute=\"ref\" class=\"$cell_id\">X1</text>\n  <text x=\"15\" y=\"30\" s:attribute=\"value\" class=\"$cell_id\" >Xk</text>\n  <path d=\"M0,10 V40 H10 V10 Z\" class=\"symbol $cell_id\"/>\n  <path d=\"M5,0 V10 M5,40 V50\" class=\"connect $cell_id\"/>\n  <g s:x=\"5\" s:y=\"0\" s:pid=\"A\" s:position=\"top\"/>\n  <g s:x=\"5\" s:y=\"50\" s:pid=\"B\" s:position=\"bottom\"/>\n</g>\n\n<g s:type=\"capacitor_h\" s:width=\"50\" s:height=\"30\" transform=\"translate(60,100)\">\n  <s:alias val=\"c_h\"/>\n  <text x=\"35\" y=\"5\" s:attribute=\"ref\" class=\"$cell_id\">X1</text>\n  <text x=\"35\" y=\"30\" s:attribute=\"value\" class=\"$cell_id\">Xu</text>\n  <path d=\"M20,0 V30 M30,0 V30\" class=\"symbol $cell_id\"/>\n  <path d=\"M0,15 H20 M30,15 H50\" class=\"connect $cell_id\"/>\n  <g s:x=\"0\" s:y=\"15\" s:pid=\"A\" s:position=\"left\"/>\n  <g s:x=\"50\" s:y=\"15\" s:pid=\"B\" s:position=\"right\"/>\n</g>\n\n<g s:type=\"capacitor_v\" s:width=\"30\" s:height=\"50\" transform=\"translate(70,130)\">\n  <s:alias val=\"c_v\"/>\n  <text x=\"25\" y=\"10\" s:attribute=\"ref\" class=\"$cell_id\">X1</text>\n  <text x=\"25\" y=\"45\" s:attribute=\"value\" class=\"$cell_id\">Xu</text>\n  <path d=\"M0,20 H30 M0,30 H30\" class=\"symbol $cell_id\"/>\n  <path d=\"M15,0 V20 M15,30 V50\" class=\"connect $cell_id\"/>\n  <g s:x=\"15\" s:y=\"0\" s:pid=\"A\" s:position=\"top\"/>\n  <g s:x=\"15\" s:y=\"50\" s:pid=\"B\" s:position=\"bottom\"/>\n</g>\n\n<g s:type=\"inductor_h\" s:width=\"50\" s:height=\"10\" transform=\"translate(115,110)\">\n  <s:alias val=\"l_h\"/>\n  <text class=\"nodelabel $cell_id\" x=\"25\" y=\"-5\" s:attribute=\"ref\">X1</text>\n  <text class=\"nodelabel $cell_id\" x=\"25\" y=\"20\" s:attribute=\"value\">XpF</text>\n  <path d=\"M5,5 A5,5 0 0 1 15,5 A5,5 0 0 1 25,5 A5,5 0 0 1 35,5 A5,5 0 0 1 45,5\" class=\"$cell_id\"/>\n  <path d=\"M0,5 H5 M45,5 H50\" class=\"connect $cell_id\"/>\n  <g s:x=\"0\" s:y=\"5\" s:pid=\"A\" s:position=\"left\"/>\n  <g s:x=\"50\" s:y=\"5\" s:pid=\"B\" s:position=\"right\"/>\n</g>\n\n<g s:type=\"inductor_v\" s:width=\"10\" s:height=\"50\" transform=\"translate(135,130)\">\n  <s:alias val=\"l_v\"/>\n  <text x=\"15\" y=\"15\" s:attribute=\"ref\" class=\"$cell_id\">X1</text>\n  <text x=\"15\" y=\"35\" s:attribute=\"value\" class=\"$cell_id\">XpF</text>\n  <path d=\"M5,5 A5,5 0 0 1 5,15 A5,5 0 0 1 5,25 A5,5 0 0 1 5,35 A5,5 0 0 1 5,45\" class=\"$cell_id\"/>\n  <path d=\"M5,0 V5 M5,45 V50\" class=\"connect $cell_id\"/>\n  <g s:x=\"5\" s:y=\"0\" s:pid=\"A\" s:position=\"top\"/>\n  <g s:x=\"5\" s:y=\"50\" s:pid=\"B\" s:position=\"bottom\"/>\n</g>\n<!-- passives -->\n\n<!-- sources -->\n<g s:type=\"voltage_source\" s:width=\"32\" s:height=\"52\" transform=\"translate(20,180)\">\n  <s:alias val=\"v\"/>\n  <text x=\"35\" y=\"20\" s:attribute=\"ref\" class=\"$cell_id\">X1</text>\n  <text x=\"35\" y=\"35\" s:attribute=\"value\" class=\"$cell_id\">XV</text>\n  <circle cx=\"16\" cy=\"26\" r=\"16\" class=\"symbol $cell_id\"/>\n  <path d=\"M16,10 V42\" class=\"detail $cell_id\"/>\n  <path d=\"M16,0 V10 M16,42 V52\" class=\"connect $cell_id\"/>\n  <g s:x=\"16\" s:y=\"0\" s:pid=\"+\" s:position=\"top\"/>\n  <g s:x=\"16\" s:y=\"52\" s:pid=\"-\" s:position=\"bottom\"/>\n</g>\n\n<g s:type=\"current_source\" s:width=\"32\" s:height=\"52\" transform=\"translate(75,180)\">\n  <s:alias val=\"i\"/>\n  <text x=\"35\" y=\"20\" s:attribute=\"ref\" class=\"$cell_id\">X1</text>\n  <text x=\"35\" y=\"35\" s:attribute=\"value\" class=\"$cell_id\">XA</text>\n  <circle cx=\"16\" cy=\"26\" r=\"16\" class=\"symbol $cell_id\"/>\n  <path d=\"M0,26 H32\" class=\"detail $cell_id\"/>\n  <path d=\"M16,0 V10 M16,42 V52\" class=\"connect $cell_id\"/>\n  <g s:x=\"16\" s:y=\"0\" s:pid=\"+\" s:position=\"top\"/>\n  <g s:x=\"16\" s:y=\"52\" s:pid=\"-\" s:position=\"bottom\"/>\n</g>\n<!-- sources -->\n\n<!-- diodes -->\n<g s:type=\"diode_h\" s:width=\"50\" s:height=\"20\" transform=\"translate(5,250)\">\n  <s:alias val=\"d_h\"/>\n  <text class=\"nodelabel $cell_id\" x=\"25\" y=\"-5\" s:attribute=\"ref\">X1</text>\n  <path d=\"M15,0 V20 L35,10 Z M35,0 V20\" class=\"symbol $cell_id\"/>\n  <path d=\"M0,10 H15 M35,10 H50\" class=\"connect $cell_id\"/>\n  <g s:x=\"0\" s:y=\"10\" s:pid=\"+\" s:position=\"left\"/>\n  <g s:x=\"50\" s:y=\"10\" s:pid=\"-\" s:position=\"right\"/>\n</g>\n\n<g s:type=\"diode_v\" s:width=\"20\" s:height=\"50\" transform=\"translate(20,280)\">\n  <s:alias val=\"d_v\"/>\n  <text x=\"25\" y=\"25\" s:attribute=\"ref\" class=\"$cell_id\">X1</text>\n  <path d=\"M0,15 H20 L10,35 Z M0,35 H20\" class=\"symbol $cell_id\"/>\n  <path d=\"M10,0 V15 M10,35 V50\" class=\"connect $cell_id\"/>\n  <g s:x=\"10\" s:y=\"0\" s:pid=\"+\" s:position=\"top\"/>\n  <g s:x=\"10\" s:y=\"50\" s:pid=\"-\" s:position=\"bottom\"/>\n</g>\n\n<g s:type=\"diode_schottky_h\" s:width=\"50\" s:height=\"20\" transform=\"translate(60,250)\">\n  <s:alias val=\"d_sk_h\"/>\n  <text class=\"nodelabel $cell_id\" x=\"25\" y=\"-5\" s:attribute=\"ref\">X1</text>\n  <path d=\"M15,0 V20 L35,10 Z M35,0 V20\" class=\"symbol $cell_id\"/>\n  <path d=\"M0,10 H15 M35,10 H50\" class=\"connect $cell_id\"/>\n  <!-- schottky -->\n  <path d=\"M35,0 H40 M35,20 H30\" class=\"symbol $cell_id\"/>\n  <g s:x=\"0\" s:y=\"10\" s:pid=\"+\" s:position=\"left\"/>\n  <g s:x=\"50\" s:y=\"10\" s:pid=\"-\" s:position=\"right\"/>\n</g>\n\n<g s:type=\"diode_schottky_v\" s:width=\"20\" s:height=\"50\" transform=\"translate(75,280)\">\n  <s:alias val=\"d_sk_v\"/>\n  <text x=\"25\" y=\"25\" s:attribute=\"ref\" class=\"$cell_id\">X1</text>\n  <path d=\"M0,15 H20 L10,35 Z M0,35 H20\" class=\"symbol $cell_id\"/>\n  <path d=\"M10,0 V15 M10,35 V50\" class=\"connect $cell_id\"/>\n  <!-- schottky -->\n  <path d=\"M0,35 V40 M20,35 V30\" class=\"symbol $cell_id\"/>\n  <g s:x=\"10\" s:y=\"0\" s:pid=\"+\" s:position=\"top\"/>\n  <g s:x=\"10\" s:y=\"50\" s:pid=\"-\" s:position=\"bottom\"/>\n</g>\n\n<g s:type=\"diode_led_h\" s:width=\"50\" s:height=\"20\" transform=\"translate(115,250)\">\n  <s:alias val=\"d_led_h\"/>\n  <text class=\"nodelabel $cell_id\" x=\"10\" y=\"-5\" s:attribute=\"ref\">X1</text>\n  <path d=\"M15,0 V20 L35,10 Z M35,0 V20\" class=\"symbol $cell_id\"/>\n  <path d=\"M0,10 H15 M35,10 H50\" class=\"connect $cell_id\"/>\n  <!-- led -->\n  <path d=\"m20,-5 7,-7\" class=\"detail $cell_id\"/>\n  <path d=\"m24,-12 6,-3 -3,6 z\" class=\"detail $cell_id\"/>\n  <path d=\"m25,0 7,-7\" class=\"detail $cell_id\"/>\n  <path d=\"m29,-7 6,-3 -3,6 z\" class=\"detail $cell_id\"/>\n  <g s:x=\"0\" s:y=\"10\" s:pid=\"+\" s:position=\"top\"/>\n  <g s:x=\"50\" s:y=\"10\" s:pid=\"-\" s:position=\"bottom\"/>\n</g>\n\n<g s:type=\"diode_led_v\" s:width=\"20\" s:height=\"50\" transform=\"translate(130,280)\">\n  <s:alias val=\"d_led_v\"/>\n  <text x=\"25\" y=\"25\" s:attribute=\"ref\" class=\"$cell_id\">X1</text>\n  <path d=\"M0,15 H20 L10,35 Z M0,35 H20\" class=\"symbol $cell_id\"/>\n  <path d=\"M10,0 V15 M10,35 V50\" class=\"connect $cell_id\"/>\n  <!-- led -->\n  <path d=\"m-5,20 -7,7\" class=\"detail $cell_id\"/>\n  <path d=\"m-12,24 -3,6 6,-3 z\" class=\"detail $cell_id\"/>\n  <path d=\"m0,25 -7,7\" class=\"detail $cell_id\"/>\n  <path d=\"m-7,29 -3,6 6,-3 z\" class=\"detail $cell_id\"/>\n  <g s:x=\"10\" s:y=\"0\" s:pid=\"+\" s:position=\"top\"/>\n  <g s:x=\"10\" s:y=\"50\" s:pid=\"-\" s:position=\"bottom\"/>\n</g>\n<!-- diodes -->\n\n<!-- transistors -->\n<g s:type=\"transistor_npn\" s:width=\"32\" s:height=\"32\" transform=\"translate(15,350)\">\n  <s:alias val=\"q_npn\"/>\n  <text x=\"35\" y=\"20\" s:attribute=\"ref\" class=\"$cell_id\">X1</text>\n  <circle r=\"16\" cx=\"16\" cy=\"16\" class=\"symbol $cell_id\"/>\n  <path d=\"M0,16 H12 M12,6 V26\" class=\"detail $cell_id\"/>\n  <path d=\"m12,10 11,-8\" class=\"detail $cell_id\"/>\n  <path d=\"m12,21 11,8\" class=\"detail $cell_id\"/>\n  <!-- npn -->\n  <path d=\"m23,29 -6,-1 3,-5 z\" style=\"fill:#000000\" class=\"$cell_id\"/>\n  <g s:x=\"22\" s:y=\"2\" s:pid=\"C\" s:position=\"top\"/>\n  <g s:x=\"0\" s:y=\"16\" s:pid=\"B\" s:position=\"left\"/>\n  <g s:x=\"23\" s:y=\"29\" s:pid=\"E\" s:position=\"bottom\"/>\n</g>\n\n<g s:type=\"transistor_pnp\" s:width=\"32\" s:height=\"32\" transform=\"translate(85,350)\">\n  <s:alias val=\"q_pnp\"/>\n  <text x=\"35\" y=\"20\" s:attribute=\"ref\" class=\"$cell_id\">X1</text>\n  <circle r=\"16\" cx=\"16\" cy=\"16\" class=\"symbol $cell_id\"/>\n  <path d=\"M0,16 H12 M12,6 V26\" class=\"detail $cell_id\"/>\n  <path d=\"m12,10 11,-8\" class=\"detail $cell_id\"/>\n  <path d=\"m12,21 11,8\" class=\"detail $cell_id\"/>\n  <!-- pnp -->\n  <path d=\"m14,9 6,-1 -3,-5 z\" style=\"fill:#000000\" class=\"$cell_id\"/>\n  <g s:x=\"22\" s:y=\"2\" s:pid=\"C\" s:position=\"top\"/>\n  <g s:x=\"0\" s:y=\"16\" s:pid=\"B\" s:position=\"left\"/>\n  <g s:x=\"23\" s:y=\"29\" s:pid=\"E\" s:position=\"bottom\"/>\n</g>\n<!-- transistors -->\n\n<!-- builtin -->\n<g s:type=\"generic\" s:width=\"30\" s:height=\"40\" transform=\"translate(150, 400)\">\n  <text x=\"15\" y=\"-4\" class=\"nodelabel $cell_id\" s:attribute=\"ref\">generic</text>\n  <rect width=\"30\" height=\"40\" x=\"0\" y=\"0\" s:generic=\"body\" class=\"$cell_id\"/>\n  <g transform=\"translate(30,10)\"\n     s:x=\"30\" s:y=\"10\" s:pid=\"out0\" s:position=\"right\">\n    <text x=\"5\" y=\"-4\" class=\"$cell_id\">out0</text>\n  </g>\n  <g transform=\"translate(30,30)\"\n     s:x=\"30\" s:y=\"30\" s:pid=\"out1\" s:position=\"right\">\n    <text x=\"5\" y=\"-4\" class=\"$cell_id\">out1</text>\n  </g>\n  <g transform=\"translate(0,10)\"\n     s:x=\"0\" s:y=\"10\" s:pid=\"in0\" s:position=\"left\">\n      <text x=\"-3\" y=\"-4\" class=\"inputPortLabel $cell_id\">in0</text>\n  </g>\n  <g transform=\"translate(0,30)\"\n     s:x=\"0\" s:y=\"30\" s:pid=\"in1\" s:position=\"left\">\n    <text x=\"-3\" y=\"-4\" class=\"inputPortLabel $cell_id\">in1</text>\n  </g>\n</g>\n<!-- builtin -->\n\n<!-- misc -->\n<g s:type=\"opamp\" s:width=\"60\" s:height=\"40\" transform=\"translate(20,450)\">\n  <s:alias val=\"op\"/>\n  <text x=\"40\" y=\"35\" s:attribute=\"ref\" class=\"$cell_id\">X1</text>\n  <path d=\"M10,0 V40 L50,20 Z\" class=\"symbol $cell_id\"/>\n  <path d=\"M0,10 H10 M0,30 H10 M50,20 H60 M30,0 V10 M30,40 V30\" class=\"connect $cell_id\"/>\n  <path d=\"m15,10 5,0 m-2.5,-2.5 0,5\" class=\"detail $cell_id\"/>\n  <path d=\"m15,30 5,0\" class=\"detail $cell_id\"/>\n  <g s:x=\"0\" s:y=\"10\" s:pid=\"+\" s:position=\"left\"/>\n  <g s:x=\"0\" s:y=\"30\" s:pid=\"-\" s:position=\"left\"/>\n  <g s:x=\"60\" s:y=\"20\" s:pid=\"OUT\" s:position=\"right\"/>\n  <g s:x=\"30\" s:y=\"0\" s:pid=\"VCC\" s:position=\"top\"/>\n  <g s:x=\"30\" s:y=\"40\" s:pid=\"VEE\" s:position=\"bottom\"/>\n</g>\n\n<g s:type=\"xtal\" s:width=\"40\" s:height=\"30\" transform=\"translate(90,450)\">\n  <s:alias val=\"xtal\"/>\n  <text class=\"nodelabel $cell_id\" x=\"20\" y=\"45\" s:attribute=\"ref\">X1</text>\n  <rect x=\"15\" y=\"0\" width=\"10\" height=\"30\" class=\"symbol $cell_id\" />\n  <path d=\"M0,15 H10 M10,5 V25 M30,5 V25 M30,15 H40\" class=\"$cell_id\"/>\n  <g s:x=\"0\" s:y=\"15\" s:pid=\"A\" s:position=\"left\"/>\n  <g s:x=\"40\" s:y=\"15\" s:pid=\"B\" s:position=\"right\"/>\n</g>\n\n<g s:type=\"transformer_1p_1s\" s:width=\"35\" s:height=\"45\" transform=\"translate(140,450)\">\n  <s:alias val=\"transformer_1p_1s\"/>\n  <text class=\"nodelabel $cell_id\" x=\"25\" y=\"55\" s:attribute=\"ref\">X1</text>\n  <path d=\"M10,0 A5,5 0 0 1 10,10 A5,5 0 0 1 10,20 A5,5 0 0 1 10,30 A5,5 0 0 1 10,40\" class=\"$cell_id\"/>\n  <path d=\"M35,0 A5,5 0 0 0 35,10 A5,5 0 0 0 35,20 A5,5 0 0 0 35,30 A5,5 0 0 0 35,40\" class=\"$cell_id\"/>\n  <path d=\"M20,0 V40 M25,0 V40\" class=\"symbol $cell_id\"/>\n  <path d=\"M0,0 H10 M0,40 H10 M35,0 H45 M35,40 H45\" class=\"connect $cell_id\"/>\n  <g s:x=\"0\" s:y=\"0\" s:pid=\"L1.1\" s:position=\"left\"/>\n  <g s:x=\"0\" s:y=\"40\" s:pid=\"L1.2\" s:position=\"left\"/>\n  <g s:x=\"40\" s:y=\"0\" s:pid=\"L2.1\" s:position=\"right\"/>\n  <g s:x=\"40\" s:y=\"40\" s:pid=\"L2.2\" s:position=\"right\"/>\n</g>\n<!-- misc -->\n</svg>\n";
                    const digital = "<svg  xmlns=\"http://www.w3.org/2000/svg\"\nxmlns:xlink=\"http://www.w3.org/1999/xlink\"\nxmlns:s=\"https://github.com/nturley/netlistsvg\"\nwidth=\"800\" height=\"500\">\n<s:properties>\n  <s:layoutEngine\n    org.eclipse.elk.layered.spacing.nodeNodeBetweenLayers=\"35\"\n    org.eclipse.elk.spacing.nodeNode= \"35\"\n    org.eclipse.elk.layered.layering.strategy= \"LONGEST_PATH\"\n  />\n  <s:low_priority_alias val=\"$dff\" />\n</s:properties>\n<style>\n    svg {\n        stroke:#000;\n        fill:none;\n    }\n    text {\n        fill:#000;\n        stroke:none;\n        font-size:10px;\n        font-weight: bold;\n        font-family: \"Courier New\", monospace;\n    }\n    line {\n        stroke-linecap: round;\n    }\n    .nodelabel {\n        text-anchor: middle;\n    }\n    .inputPortLabel {\n        text-anchor: end;\n    }\n    .splitjoinBody {\n        fill:#000;\n    }\n</style>\n<g s:type=\"mux\" transform=\"translate(50, 50)\" s:width=\"20\" s:height=\"40\">\n  <s:alias val=\"$pmux\"/>\n  <s:alias val=\"$mux\"/>\n  <s:alias val=\"$_MUX_\"/>\n\n  <path style=\"fill:#eeaaff\" d=\"M0,0 L20,10 L20,30 L0,40 Z\" class=\"$cell_id\"/>\n\n  <text x=\"5\" y=\"13\" class=\"nodelabel $cell_id\" s:attribute=\"\">0</text>\n  <text x=\"5\" y=\"32\" class=\"nodelabel $cell_id\" s:attribute=\"\">1</text>\n  <g s:x=\"0\" s:y=\"10\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"30\" s:pid=\"B\"/>\n  <g s:x=\"10\" s:y=\"35\" s:pid=\"S\"/>\n  <g s:x=\"20\" s:y=\"20\" s:pid=\"Y\"/>\n</g>\n\n<g  s:type=\"mux-bus\" transform=\"translate(100, 50)\" s:width=\"24\" s:height=\"40\" >\n  <s:alias val=\"$pmux-bus\"/>\n  <s:alias val=\"$mux-bus\"/>\n  <s:alias val=\"$_MUX_-bus\"/>\n\n  <path style=\"fill:#eeaaff\" d=\"M0,0 L20,10 L20,30 L0,40 Z\" class=\"$cell_id\"/>\n  <path d=\"M4,2 L4,0 L22,9 L22,31 L4,40 L4,38\" class=\"$cell_id\"/>\n  <path d=\"M8,2 L8,0 L24,8 L24,32 L8,40 L8,38\" class=\"$cell_id\"/>\n\n  <text x=\"5\" y=\"13\" class=\"nodelabel $cell_id\" s:attribute=\"\">A</text>\n  <text x=\"5\" y=\"32\" class=\"nodelabel $cell_id\" s:attribute=\"\">B</text>\n  <g s:x=\"-1\" s:y=\"10\" s:pid=\"A\"/>\n  <g s:x=\"-1\" s:y=\"30\" s:pid=\"B\"/>\n  <g s:x=\"12\" s:y=\"38\" s:pid=\"S\"/>\n  <g s:x=\"24.5\" s:y=\"20\" s:pid=\"Y\"/>\n</g>\n\n<!-- and -->\n<g s:type=\"and\" transform=\"translate(150,50)\" s:width=\"30\" s:height=\"25\">\n  <s:alias val=\"$and\"/>\n  <s:alias val=\"$logic_and\"/>\n  <s:alias val=\"$_AND_\"/>\n  <s:alias val=\"$reduce_and\"/>\n\n  <path style=\"fill:#80D4FF\" d=\"M0,0 L0,25 L15,25 A15 12.5 0 0 0 15,0 Z\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"20\" s:pid=\"B\"/>\n  <g s:x=\"30\" s:y=\"12.5\" s:pid=\"Y\"/>\n\n  <text x=\"3.0\" y=\"15\" class=\"smalltext\">and</text>\n</g>\n\n<g s:type=\"nand\" transform=\"translate(150,100)\" s:width=\"30\" s:height=\"25\">\n  <s:alias val=\"$nand\"/>\n  <s:alias val=\"$logic_nand\"/>\n  <s:alias val=\"$_NAND_\"/>\n  <s:alias val=\"$_ANDNOT_\"/>\n\n  <path style=\"fill:#80D4FF\" d=\"M0,0 L0,25 L15,25 A15 12.5 0 0 0 15,0 Z\" class=\"$cell_id\"/>\n  <circle cx=\"34\" cy=\"12.5\" r=\"3\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"20\" s:pid=\"B\"/>\n  <g s:x=\"36\" s:y=\"12.5\" s:pid=\"Y\"/>\n\n  <text x=\"3.0\" y=\"15\" class=\"smalltext\">nand</text>\n</g>\n\n<!-- or -->\n<g s:type=\"or\" transform=\"translate(250,50)\" s:width=\"30\" s:height=\"25\">\n  <s:alias val=\"$or\"/>\n  <s:alias val=\"$logic_or\"/>\n  <s:alias val=\"$_OR_\"/>\n  <s:alias val=\"$reduce_or\"/>\n  <s:alias val=\"$reduce_bool\"/>\n\n  <path style=\"fill:#80D4FF\" d=\"M0,25 L0,25 L15,25 A15 12.5 0 0 0 15,0 L0,0\" class=\"$cell_id\"/>\n  <path style=\"fill:#ffffff\" d=\"M0,0 A30 25 0 0 1 0,25\" class=\"$cell_id\"/>\n\n  <g s:x=\"2\" s:y=\"5\" s:pid=\"A\"/>\n  <g s:x=\"2\" s:y=\"20\" s:pid=\"B\"/>\n  <g s:x=\"30\" s:y=\"12.5\" s:pid=\"Y\"/>\n\n  <text x=\"8.0\" y=\"15\" class=\"smalltext\">or</text>\n</g>\n\n<g s:type=\"reduce_nor\" transform=\"translate(250, 100)\" s:width=\"33\" s:height=\"25\">\n  <s:alias val=\"$nor\"/>\n  <s:alias val=\"$reduce_nor\"/>\n  <s:alias val=\"$_NOR_\"/>\n  <s:alias val=\"$_ORNOT_\"/>\n\n  <path style=\"fill:#80D4FF\"  d=\"M0,25 L0,25 L15,25 A15 12.5 0 0 0 15,0 L0,0\" class=\"$cell_id\"/>\n  <path style=\"fill:#ffffff\"  d=\"M0,0 A30 25 0 0 1 0,25\" class=\"$cell_id\"/>\n  <circle cx=\"34\" cy=\"12.5\" r=\"3\" class=\"$cell_id\"/>\n\n  <g s:x=\"2\" s:y=\"5\" s:pid=\"A\"/>\n  <g s:x=\"2\" s:y=\"20\" s:pid=\"B\"/>\n  <g s:x=\"36\" s:y=\"12.5\" s:pid=\"Y\"/>\n\n  <text x=\"8.0\" y=\"15\" class=\"smalltext\">nor</text>\n</g>\n\n<!--xor -->\n<g s:type=\"reduce_xor\" transform=\"translate(350, 50)\" s:width=\"33\" s:height=\"25\">\n  <s:alias val=\"$xor\"/>\n  <s:alias val=\"$reduce_xor\"/>\n  <s:alias val=\"$_XOR_\"/>\n\n  <path style=\"fill:#80D4FF\" d=\"M3,0 A30 25 0 0 1 3,25 A30 25 0 0 0 33,12.5 A30 25 0 0 0 3,0\" class=\"$cell_id\"/>\n  <path style=\"fill:#ffffff\" d=\"M0,0 A30 25 0 0 1 0,25\" class=\"$cell_id\"/>\n\n  <g s:x=\"2\" s:y=\"5\" s:pid=\"A\"/>\n  <g s:x=\"2\" s:y=\"20\" s:pid=\"B\"/>\n  <g s:x=\"33\" s:y=\"12.5\" s:pid=\"Y\"/>\n\n  <text x=\"10.0\" y=\"15\" class=\"smalltext\">xor</text>\n</g>\n<g s:type=\"reduce_nxor\" transform=\"translate(350, 100)\" s:width=\"33\" s:height=\"25\">\n  <s:alias val=\"$xnor\"/>\n  <s:alias val=\"$reduce_xnor\"/>\n  <s:alias val=\"$_XNOR_\"/>\n\n  <path style=\"fill:#80D4FF\" d=\"M3,0 A30 25 0 0 1 3,25 A30 25 0 0 0 33,12.5 A30 25 0 0 0 3,0\" class=\"$cell_id\"/>\n  <path style=\"fill:#ffffff\" d=\"M0,0 A30 25 0 0 1 0,25\" class=\"$cell_id\"/>\n  <circle cx=\"36\" cy=\"12.5\" r=\"3\" class=\"$cell_id\"/>\n\n  <g s:x=\"2\" s:y=\"5\" s:pid=\"A\"/>\n  <g s:x=\"2\" s:y=\"20\" s:pid=\"B\"/>\n  <g s:x=\"38\" s:y=\"12.5\" s:pid=\"Y\"/>\n\n  <text x=\"8.0\" y=\"15\" class=\"smalltext\">nxor</text>\n</g>\n\n<!--buffer -->\n<g s:type=\"not\" transform=\"translate(450,100)\" s:width=\"30\" s:height=\"20\">\n  <s:alias val=\"$_NOT_\"/>\n  <s:alias val=\"$not\"/>\n  <s:alias val=\"$logic_not\"/>\n\n  <path style=\"fill:#FFE680\" d=\"M0,0 L0,20 L20,10 Z\" class=\"$cell_id\"/>\n  <circle  cx=\"24\" cy=\"10\" r=\"3\" class=\"$cell_id\"/>\n\n  <g s:x=\"-1\" s:y=\"10\" s:pid=\"A\"/>\n  <g s:x=\"27\" s:y=\"10\" s:pid=\"Y\"/>\n</g>\n\n<g s:type=\"tribuf\" transform=\"translate(450, 50)\" s:width=\"15\" s:height=\"30\">\n  <s:alias val=\"$tribuf\"/>\n  <s:alias val=\"$_TRIBUF_\"/>\n\n  <s:alias val=\"tribuf-bus\"/>\n  <s:alias val=\"$tribuf-bus\"/>\n  <s:alias val=\"$_TRIBUF_-bus\"/>\n\n  <path style=\"fill:#FFE680\" d=\"M0,0 L25,15 L0,30 Z\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"15\" s:pid=\"A\"/>\n  <g s:x=\"11\" s:y=\"6\" s:pid=\"EN\"/>\n  <g s:x=\"25\" s:y=\"15\" s:pid=\"Y\"/>\n</g>\n\n<!-- Arithmetic -->\n<g s:type=\"add\" transform=\"translate(50, 150)\" s:width=\"30\" s:height=\"30\">\n  <s:alias val=\"$add\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"7.5\" x2=\"17.5\" y1=\"12.5\" y2=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"12.5\" x2=\"12.5\" y1=\"7.5\" y2=\"17.5\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n\n<g s:type=\"pos\" transform=\"translate(100, 150)\" s:width=\"25\" s:height=\"25\">\n  <s:alias val=\"$pos\"/>\n\n  <circle r=\"12.5\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"7.5\" x2=\"17.5\" y1=\"12.5\" y2=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"12.5\" x2=\"12.5\" y1=\"7.5\" y2=\"17.5\" class=\"$cell_id\"/>\n\n  <g s:x=\"-1\" s:y=\"12.5\" s:pid=\"A\"/>\n  <g s:x=\"26\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n\n<g s:type=\"sub\" transform=\"translate(150,150)\" s:width=\"30\" s:height=\"30\">\n  <s:alias val=\"$sub\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"7.5\" x2=\"17.5\" y1=\"12.5\" y2=\"12.5\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n<g s:type=\"neg\" transform=\"translate(200,150)\" s:width=\"25\" s:height=\"25\">\n  <s:alias val=\"$neg\"/>\n\n  <circle r=\"12.5\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"7.5\" x2=\"17.5\" y1=\"12.5\" y2=\"12.5\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"12.5\" s:pid=\"A\"/>\n  <g s:x=\"25\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n<g s:type=\"eq\" transform=\"translate(250,150)\" s:width=\"30\" s:height=\"30\">\n  <s:alias val=\"$eq\"/>\n  <s:alias val=\"$eqx\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"7.5\" x2=\"17.5\" y1=\"10\" y2=\"10\" class=\"$cell_id\"/>\n  <line x1=\"7.5\" x2=\"17.5\" y1=\"15\" y2=\"15\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n<g s:type=\"ne\" transform=\"translate(500,150)\" s:width=\"25\" s:height=\"25\">\n  <s:alias val=\"$ne\"/>\n  <s:alias val=\"$nex\"/>\n\n  <circle r=\"12.5\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"7.5\" x2=\"17.5\" y1=\"10\" y2=\"10\" class=\"$cell_id\"/>\n  <line x1=\"7.5\" x2=\"17.5\" y1=\"15\" y2=\"15\" class=\"$cell_id\"/>\n  <line x1=\"9\" x2=\"16\" y1=\"18\" y2=\"7\" class=\"$cell_id\"/>\n\n  <g s:x=\"2\" s:y=\"5\" s:pid=\"A\"/>\n  <g s:x=\"2\" s:y=\"20\" s:pid=\"B\"/>\n  <g s:x=\"25\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n<g s:type=\"mul\" transform=\"translate(300, 150)\" s:width=\"30\" s:height=\"30\">\n  <s:alias val=\"$mul\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"7.5\"  x2=\"17.5\" y1=\"7.5\" y2=\"17.5\" class=\"$cell_id\"/>\n  <line x1=\"17.5\" x2=\"7.5\"  y1=\"7.5\" y2=\"17.5\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n<g s:type=\"div\" transform=\"translate(350, 150)\" s:width=\"30\" s:height=\"30\">\n  <s:alias val=\"$div\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"15\" x2=\"10\"  y1=\"7.5\" y2=\"17.5\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n<g s:type=\"mod\" transform=\"translate(400, 150)\" s:width=\"30\" s:height=\"30\">\n  <s:alias val=\"$mod\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"15\" x2=\"10\"  y1=\"7.5\" y2=\"17.5\" class=\"$cell_id\"/>\n  <circle r=\"2\" cx=\"8\" cy=\"9\" class=\"$cell_id\"/>\n  <circle r=\"2\" cx=\"17\" cy=\"16\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n<g s:type=\"pow\" transform=\"translate(450, 150)\" s:width=\"30\" s:height=\"30\">\n  <s:alias val=\"$pow\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"7.5\" x2=\"12.5\"  y1=\"17.5\" y2=\"7.5\" class=\"$cell_id\"/>\n  <line x1=\"17.5\" x2=\"12.5\"  y1=\"17.5\" y2=\"7.5\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n\n<!-- D Flip Flops -->\n<g s:type=\"dff\" transform=\"translate(50,300)\" s:width=\"30\" s:height=\"40\">\n  <s:alias val=\"$dff\"/>\n  <s:alias val=\"$_DFF_\"/>\n  <s:alias val=\"$_DFF_P_\"/>\n\n  <s:alias val=\"$adff\"/>\n  <s:alias val=\"$_DFF_\"/>\n  <s:alias val=\"$_DFF_P_\"/>\n\n  <s:alias val=\"$sdff\"/>\n  <s:alias val=\"$_DFF_\"/>\n  <s:alias val=\"$_DFF_P_\"/>\n\n  <rect style=\"fill:#29F7A4\" width=\"30\" height=\"40\" x=\"0\" y=\"0\" class=\"$cell_id\"/>\n  <path d=\"M0,35 L5,30 L0,25\" class=\"$cell_id\"/>\n\n  <g s:x=\"31\" s:y=\"10\" s:pid=\"Q\"/>\n  <g s:x=\"-1\" s:y=\"30\" s:pid=\"CLK\"/>\n  <g s:x=\"-1\" s:y=\"30\" s:pid=\"C\"/>\n  <g s:x=\"-1\" s:y=\"10\" s:pid=\"D\"/>\n  <g s:x=\"15\" s:y=\"40\" s:pid=\"ARST\"/>\n  <g s:x=\"15\" s:y=\"40\" s:pid=\"SRST\"/>\n\n  <text x=\"2.0\" y=\"10\" class=\"smalltext\">D</text>\n  <text x=\"20.0\" y=\"10\" class=\"smalltext rtext\">Q</text>\n  <text x=\"6.0\" y=\"33\" class=\"smalltext\">CLK</text>\n  <text x=\"5.0\" y=\"22\" class=\"verysmalltext\">dff</text>\n</g>\n<g s:type=\"dff-bus\" transform=\"translate(100,300)\" s:width=\"34\" s:height=\"44\">\n  <s:alias val=\"$dff-bus\"/>\n  <s:alias val=\"$_DFF_-bus\"/>\n  <s:alias val=\"$_DFF_P_-bus\"/>\n\n  <s:alias val=\"adff-bus\"/>\n  <s:alias val=\"$adff-bus\"/>\n  <s:alias val=\"$_DFF_-bus\"/>\n  <s:alias val=\"$_DFF_P_-bus\"/>\n\n  <s:alias val=\"sdff-bus\"/>\n  <s:alias val=\"$sdff-bus\"/>\n  <s:alias val=\"$_DFF_-bus\"/>\n  <s:alias val=\"$_DFF_P_-bus\"/>\n\n  <rect style=\"fill:#29F7A4\" width=\"30\" height=\"40\" x=\"0\" y=\"0\" class=\"$cell_id\"/>\n  <path d=\"M0,35 L5,30 L0,25\" class=\"$cell_id\"/>\n  <path d=\"M30,2 L32,2 L32,42 L2,42 L2,40\" />\n  <path d=\"M32,4 L34,4 L34,44 L4,44 L4,42\" />\n\n  <g s:x=\"35\" s:y=\"10\" s:pid=\"Q\"/>\n  <g s:x=\"-1\" s:y=\"30\" s:pid=\"CLK\"/>\n  <g s:x=\"-1\" s:y=\"30\" s:pid=\"C\"/>\n  <g s:x=\"-1\" s:y=\"10\" s:pid=\"D\"/>\n  <g s:x=\"17\" s:y=\"44\" s:pid=\"ARST\"/>\n  <g s:x=\"17\" s:y=\"44\" s:pid=\"SRST\"/>\n\n  <text x=\"2.0\" y=\"10\" class=\"smalltext\">D</text>\n  <text x=\"20.0\" y=\"10\" class=\"smalltext rtext\">Q</text>\n  <text x=\"6.0\" y=\"33\" class=\"smalltext\">CLK</text>\n  <text x=\"3.0\" y=\"22\" class=\"verysmalltext\">dffs</text>\n</g>\n<g s:type=\"dffn\" transform=\"translate(150,300)\" s:width=\"30\" s:height=\"40\">\n  <s:alias val=\"$dffn\"/>\n  <s:alias val=\"$_DFF_N_\"/>\n\n  <rect style=\"fill:#29F7A4\" width=\"30\" height=\"40\" x=\"0\" y=\"0\" class=\"$cell_id\"/>\n  <path d=\"M0,35 L5,30 L0,25\" class=\"$cell_id\"/>\n  <circle cx=\"-3\" cy=\"30\" r=\"3\" class=\"$cell_id\"/>\n\n  <g s:x=\"30\" s:y=\"10\" s:pid=\"Q\"/>\n  <g s:x=\"-6\" s:y=\"30\" s:pid=\"CLK\"/>\n  <g s:x=\"-6\" s:y=\"30\" s:pid=\"C\"/>\n  <g s:x=\"0\" s:y=\"10\" s:pid=\"D\"/>\n\n  <text x=\"2.0\" y=\"10\" class=\"smalltext\">D</text>\n  <text x=\"20.0\" y=\"10\" class=\"smalltext rtext\">Q</text>\n  <text x=\"6.0\" y=\"33\" class=\"smalltext\">CLK</text>\n  <text x=\"3.0\" y=\"22\" class=\"verysmalltext\">dffn</text>\n</g>\n<g s:type=\"dffn-bus\" transform=\"translate(200,300)\" s:width=\"30\" s:height=\"40\">\n  <s:alias val=\"$dffn-bus\"/>\n  <s:alias val=\"$_DFF_N_-bus\"/>\n\n  <rect style=\"fill:#29F7A4\" width=\"30\" height=\"40\" x=\"0\" y=\"0\" class=\"$cell_id\"/>\n  <path d=\"M0,35 L5,30 L0,25\" class=\"$cell_id\"/>\n  <circle cx=\"-3\" cy=\"30\" r=\"3\" class=\"$cell_id\"/>\n  <path d=\"M30,2 L32,2 L32,42 L2,42 L2,40\" />\n  <path d=\"M32,4 L34,4 L34,44 L4,44 L4,42\" />\n\n  <g s:x=\"35\" s:y=\"10\" s:pid=\"Q\"/>\n  <g s:x=\"-6\" s:y=\"30\" s:pid=\"CLK\"/>\n  <g s:x=\"-6\" s:y=\"30\" s:pid=\"C\"/>\n  <g s:x=\"0\" s:y=\"10\" s:pid=\"D\"/>\n\n  <text x=\"2.0\" y=\"10\" class=\"smalltext\">D</text>\n  <text x=\"20.0\" y=\"10\" class=\"smalltext rtext\">Q</text>\n  <text x=\"6.0\" y=\"33\" class=\"smalltext\">CLK</text>\n  <text x=\"0.0\" y=\"22\" class=\"verysmalltext\">dffns</text>\n</g>\n\n<!-- D Latches -->\n<g s:type=\"dlatch\" transform=\"translate(250,300)\" s:width=\"30\" s:height=\"40\">\n  <s:alias val=\"$dlatch\"/>\n  <s:alias val=\"$_DLATCH_\"/>\n  <s:alias val=\"adlatch\"/>\n  <s:alias val=\"$adlatch\"/>\n\n  <rect style=\"fill:#33BCA8\" width=\"30\" height=\"40\" x=\"0\" y=\"0\" class=\"$cell_id\"/>\n\n  <path d=\"M 1,35 H 4 V 25 h 5 v 10 h 3\"/>\n\n  <g s:x=\"30\" s:y=\"10\" s:pid=\"Q\"/>\n  <g s:x=\"0\" s:y=\"10\" s:pid=\"D\"/>\n  <g s:x=\"-1\" s:y=\"30\" s:pid=\"EN\"/>\n  <g s:x=\"15\" s:y=\"40\" s:pid=\"ARST\"/>\n\n  <text x=\"2.0\" y=\"10\" class=\"smalltext\">D</text>\n  <text x=\"20.0\" y=\"10\" class=\"smalltext rtext\">Q</text>\n  <text x=\"15.0\" y=\"33\" class=\"smalltext\">EN</text>\n  <text x=\"6.0\" y=\"20\" class=\"verysmalltext\">dla</text>\n</g>\n<g s:type=\"dlatch-bus\" transform=\"translate(300,300)\" s:width=\"30\" s:height=\"40\">\n  <s:alias val=\"$dlatch-bus\"/>\n  <s:alias val=\"$_DLATCH_-bus\"/>\n  <s:alias val=\"adlatch-bus\"/>\n  <s:alias val=\"$adlatch-bus\"/>\n\n  <rect style=\"fill:#33BCA8\" width=\"30\" height=\"40\" x=\"0\" y=\"0\" class=\"$cell_id\"/>\n\n  <path d=\"M 1,35 H 4 V 25 h 5 v 10 h 3\"/>\n  <path d=\"M30,2 L32,2 L32,42 L2,42 L2,40\" />\n  <path d=\"M32,4 L34,4 L34,44 L4,44 L4,42\" />\n\n  <g s:x=\"35\" s:y=\"10\" s:pid=\"Q\"/>\n  <g s:x=\"0\" s:y=\"10\" s:pid=\"D\"/>\n  <g s:x=\"-1\" s:y=\"30\" s:pid=\"EN\"/>\n  <g s:x=\"17\" s:y=\"44\" s:pid=\"ARST\"/>\n\n  <text x=\"2.0\" y=\"10\" class=\"smalltext\">D</text>\n  <text x=\"20.0\" y=\"10\" class=\"smalltext rtext\">Q</text>\n  <text x=\"15.0\" y=\"33\" class=\"smalltext\">EN</text>\n  <text x=\"3.0\" y=\"20\" class=\"verysmalltext\">dlas</text>\n</g>\n<g s:type=\"dlatchn\" transform=\"translate(350,300)\" s:width=\"30\" s:height=\"40\">\n  <s:alias val=\"$dlatchn\"/>\n  <s:alias val=\"$_DLATCH_\"/>\n\n  <rect style=\"fill:#33BCA8\" width=\"30\" height=\"40\" x=\"0\" y=\"0\" class=\"$cell_id\"/>\n\n  <path d=\"M 1,25 H 4 V 35 H 9 V 25 h 3\" />\n\n  <g s:x=\"30\" s:y=\"10\" s:pid=\"Q\"/>\n  <g s:x=\"0\" s:y=\"10\" s:pid=\"D\"/>\n  <g s:x=\"-1\" s:y=\"30\" s:pid=\"EN\"/>\n\n  <text x=\"2.0\" y=\"10\" class=\"smalltext\">D</text>\n  <text x=\"20.0\" y=\"10\" class=\"smalltext rtext\">Q</text>\n  <text x=\"15.0\" y=\"33\" class=\"smalltext\">EN</text>\n  <text x=\"3.0\" y=\"20\" class=\"verysmalltext\">dlan</text>\n</g>\n<g s:type=\"dlatchn-bus\" transform=\"translate(400,300)\" s:width=\"30\" s:height=\"40\">\n  <s:alias val=\"$dlatchn-bus\"/>\n  <s:alias val=\"$_DLATCH_-bus\"/>\n\n  <rect style=\"fill:#33BCA8\" width=\"30\" height=\"40\" x=\"0\" y=\"0\" class=\"$cell_id\"/>\n\n  <path d=\"M 1,25 H 4 V 35 H 9 V 25 h 3\" />\n  <path d=\"M30,2 L32,2 L32,42 L2,42 L2,40\" />\n  <path d=\"M32,4 L34,4 L34,44 L4,44 L4,42\" />\n\n  <g s:x=\"35\" s:y=\"10\" s:pid=\"Q\"/>\n  <g s:x=\"0\" s:y=\"10\" s:pid=\"D\"/>\n  <g s:x=\"-1\" s:y=\"30\" s:pid=\"EN\"/>\n\n  <text x=\"2.0\" y=\"10\" class=\"smalltext\">D</text>\n  <text x=\"20.0\" y=\"10\" class=\"smalltext rtext\">Q</text>\n  <text x=\"15.0\" y=\"33\" class=\"smalltext\">EN</text>\n  <text x=\"0.0\" y=\"20\" class=\"verysmalltext\">dlans</text>\n</g>\n\n<!-- compare -->\n<g s:type=\"lt\" transform=\"translate(50,200)\" s:width=\"25\" s:height=\"25\">\n  <s:alias val=\"$lt\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"6\" x2=\"17\" y1=\"12\"  y2=\"7\" class=\"$cell_id\"/>\n  <line x1=\"6\" x2=\"17\" y1=\"12\" y2=\"17\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n  \n</g>\n<g s:type=\"le\" transform=\"translate(100,200)\" s:width=\"25\" s:height=\"25\">\n  <s:alias val=\"$le\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"6\" x2=\"17\" y1=\"11\"  y2=\"6\" class=\"$cell_id\"/>\n  <line x1=\"6\" x2=\"17\" y1=\"11\" y2=\"16\" class=\"$cell_id\"/>\n  <line x1=\"6\" x2=\"17\" y1=\"14\" y2=\"19\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n<g s:type=\"ge\" transform=\"translate(150,200)\" s:width=\"25\" s:height=\"25\">\n  <s:alias val=\"$ge\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"8\" x2=\"19\"  y1=\"6\" y2=\"11\" class=\"$cell_id\"/>\n  <line x1=\"8\" x2=\"19\" y1=\"16\" y2=\"11\" class=\"$cell_id\"/>\n  <line x1=\"8\" x2=\"19\" y1=\"19\" y2=\"14\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n<g s:type=\"gt\" transform=\"translate(200,200)\" s:width=\"25\" s:height=\"25\">\n  <s:alias val=\"$gt\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"8\" x2=\"19\"  y1=\"7\" y2=\"12\" class=\"$cell_id\"/>\n  <line x1=\"8\" x2=\"19\" y1=\"17\" y2=\"12\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n\n<!-- shift -->\n<g s:type=\"shr\" transform=\"translate(250,200)\" s:width=\"25\" s:height=\"25\">\n  <s:alias val=\"$shr\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"8\" x2=\"13\"  y1=\"7\"  y2=\"12\" class=\"$cell_id\"/>\n  <line x1=\"8\" x2=\"13\"  y1=\"17\" y2=\"12\" class=\"$cell_id\"/>\n  <line x1=\"14\" x2=\"19\" y1=\"7\"  y2=\"12\" class=\"$cell_id\"/>\n  <line x1=\"14\" x2=\"19\" y1=\"17\" y2=\"12\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n<g s:type=\"shl\" transform=\"translate(300,200)\" s:width=\"25\" s:height=\"25\">\n  <s:alias val=\"$shl\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"6\" x2=\"11\"  y1=\"12\" y2=\"7\"  class=\"$cell_id\"/>\n  <line x1=\"6\" x2=\"11\"  y1=\"12\" y2=\"17\" class=\"$cell_id\"/>\n  <line x1=\"12\" x2=\"17\" y1=\"12\" y2=\"7\"  class=\"$cell_id\"/>\n  <line x1=\"12\" x2=\"17\" y1=\"12\" y2=\"17\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n<g s:type=\"sshr\" transform=\"translate(350,200)\" s:width=\"25\" s:height=\"25\">\n  <s:alias val=\"$sshr\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"5\"  x2=\"10\" y1=\"7\"  y2=\"12\" class=\"$cell_id\"/>\n  <line x1=\"5\"  x2=\"10\" y1=\"17\" y2=\"12\" class=\"$cell_id\"/>\n  <line x1=\"11\" x2=\"16\" y1=\"7\"  y2=\"12\" class=\"$cell_id\"/>\n  <line x1=\"11\" x2=\"16\" y1=\"17\" y2=\"12\" class=\"$cell_id\"/>\n  <line x1=\"17\" x2=\"22\" y1=\"7\"  y2=\"12\" class=\"$cell_id\"/>\n  <line x1=\"17\" x2=\"22\" y1=\"17\" y2=\"12\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n<g s:type=\"sshl\" transform=\"translate(400,200)\" s:width=\"25\" s:height=\"25\">\n  <s:alias val=\"$sshl\"/>\n\n  <circle r=\"15\" cx=\"12.5\" cy=\"12.5\" class=\"$cell_id\"/>\n  <line x1=\"3\"  x2=\"8\"   y1=\"12\" y2=\"7\"  class=\"$cell_id\"/>\n  <line x1=\"3\"  x2=\"8\"   y1=\"12\" y2=\"17\" class=\"$cell_id\"/>\n  <line x1=\"9\"  x2=\"14\" y1=\"12\" y2=\"7\"  class=\"$cell_id\"/>\n  <line x1=\"9\"  x2=\"14\" y1=\"12\" y2=\"17\" class=\"$cell_id\"/>\n  <line x1=\"15\" x2=\"20\" y1=\"12\" y2=\"7\"  class=\"$cell_id\"/>\n  <line x1=\"15\" x2=\"20\" y1=\"12\" y2=\"17\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"2.5\" s:pid=\"A\"/>\n  <g s:x=\"0\" s:y=\"22.5\" s:pid=\"B\"/>\n  <g s:x=\"27.5\" s:y=\"12.5\" s:pid=\"Y\"/>\n</g>\n\n<!-- port -->\n<g s:type=\"inputExt\" transform=\"translate(50,250)\" s:width=\"30\" s:height=\"20\">\n  <text x=\"15\" y=\"-4\" class=\"nodelabel $cell_id\" s:attribute=\"ref\">input</text>\n  <s:alias val=\"$_inputExt_\"/>\n  <path style=\"fill:#FDF766\" d=\"M0,0 L0,16 L15,16 L24,8 L15,0 Z\" class=\"$cell_id\"/>\n  <g s:x=\"24\" s:y=\"8\" s:pid=\"Y\"/>\n</g>\n<g s:type=\"outputExt\" transform=\"translate(250,250)\" s:width=\"30\" s:height=\"20\">\n  <text x=\"15\" y=\"-4\" class=\"nodelabel $cell_id\" s:attribute=\"ref\">output</text>\n  <s:alias val=\"$_outputExt_\"/>\n  <path style=\"fill:#66FDD9\" d=\"M24,0 L24,16 L10,16 L0,8 L10,0 Z\" class=\"$cell_id\"/>\n\n  <g s:x=\"0\" s:y=\"8\" s:pid=\"A\"/>\n</g>\n<g s:type=\"constant\" transform=\"translate(150,250)\" s:width=\"30\" s:height=\"20\">\n  <text x=\"15\" y=\"-4\" class=\"nodelabel $cell_id\" s:attribute=\"ref\">constant</text>\n\n  <s:alias val=\"$_constant_\"/>\n  <rect style=\"fill:#7F66FD\" width=\"30\" height=\"20\" rx=\"5\" ry=\"5\" class=\"$cell_id\"/>\n\n  <g s:x=\"31\" s:y=\"10\" s:pid=\"Y\"/>\n</g>\n\n<g s:type=\"split\" transform=\"translate(350,250)\" s:width=\"5\" s:height=\"40\">\n  <rect width=\"5\" height=\"40\" class=\"splitjoinBody\" s:generic=\"body\"/>\n  <s:alias val=\"$_split_\"/>\n\n  <g s:x=\"0\" s:y=\"20\" s:pid=\"in\"/>\n  <g transform=\"translate(5, 10)\" s:x=\"4\" s:y=\"10\" s:pid=\"out0\">\n    <text x=\"5\" y=\"-4\">hi:lo</text>\n  </g>\n  <g transform=\"translate(5, 30)\" s:x=\"4\" s:y=\"30\" s:pid=\"out1\">\n    <text x=\"5\" y=\"-4\">hi:lo</text>\n  </g>\n</g>\n\n<g s:type=\"join\" transform=\"translate(450,250)\" s:width=\"4\" s:height=\"40\">\n  <rect width=\"5\" height=\"40\" class=\"splitjoinBody\" s:generic=\"body\"/>\n  <s:alias val=\"$_join_\"/>\n  <g s:x=\"5\" s:y=\"20\"  s:pid=\"out\"/>\n  <g transform=\"translate(0, 10)\" s:x=\"0\" s:y=\"10\" s:pid=\"in0\">\n    <text x=\"-3\" y=\"-4\" class=\"inputPortLabel\">hi:lo</text>\n  </g>\n  <g transform=\"translate(0, 30)\" s:x=\"0\" s:y=\"30\" s:pid=\"in1\">\n    <text x=\"-3\" y=\"-4\" class=\"inputPortLabel\">hi:lo</text>\n  </g>\n</g>\n\n<!-- <defs>\n<filter id=\"f4\" x=\"0\" y=\"0\" width=\"110%\" height=\"120%\">\n  <feOffset result=\"offOut\" in=\"SourceGraphic\" dx=\"20\" dy=\"20\" />\n    <feColorMatrix result=\"matrixOut\" in=\"offOut\" type=\"matrix\"\n    values=\"0.2 0 0 0 0 0 0.2 0 0 0 0 0 0.2 0 0 0 0 0 1 0\" />\n    <feGaussianBlur result=\"blurOut\" in=\"matrixOut\" stdDeviation=\"10\" />\n    <feBlend in=\"SourceGraphic\" in2=\"blurOut\" mode=\"normal\" />\n  </filter>\n</defs> -->\n\n<g s:type=\"generic\" transform=\"translate(550,250)\" s:width=\"60\" s:height=\"45\">\n\n  <text x=\"30\" y=\"-4\" class=\"nodelabel $cell_id\" s:attribute=\"ref\">generic</text>\n  <rect style=\"fill:#EDF5FF\" width=\"60\" height=\"45\" rx=\"5\" ry=\"5\" s:generic=\"body\" class=\"$cell_id\"/>\n  \n  <!-- <g transform=\"translate(60, 25)\" s:x=\"60\" s:y=\"15\" s:pid=\"buso\">\n    <rect style=\"fill:#EDF5FF\" width=\"5\" height=\"10\" s:generic=\"body\" class=\"$bus_id\"/>\n  </g>\n  \n  <g transform=\"translate(-5, 25)\" s:x=\"60\" s:y=\"15\" s:pid=\"busi\">\n    <rect style=\"fill:#EDF5FF\" width=\"5\" height=\"10\" s:generic=\"body\" class=\"$bus_id\"/>\n  </g> -->\n\n  <g transform=\"translate(60, 15)\" s:x=\"60\" s:y=\"15\" s:pid=\"out0\">\n    <text x=\"5\" y=\"-4\" style=\"fill:#000; stroke:none\" class=\"$cell_id\">out0</text>\n  </g>\n  <g transform=\"translate(60, 35)\" s:x=\"60\" s:y=\"35\" s:pid=\"out1\">\n    <text x=\"5\" y=\"-4\" style=\"fill:#000;stroke:none\" class=\"$cell_id\">out1</text>\n  </g>\n  <g transform=\"translate(0, 15)\" s:x=\"0\" s:y=\"15\" s:pid=\"in0\">\n    <text x=\"-3\" y=\"-4\" class=\"inputPortLabel $cell_id\">in0</text>\n  </g>\n  <g transform=\"translate(0, 35)\" s:x=\"0\" s:y=\"35\" s:pid=\"in1\">\n    <text x=\"-3\" y=\"-4\" class=\"inputPortLabel $cell_id\">in1</text>\n  </g>\n</g>\n\n</svg>";

                    function render(skinData, netlistData, cb) {
                        // 检测输入的json数据是否合法
                        var valid = ajv.validate(json5.parse(schema), netlistData);
                        if (!valid) {
                            throw Error(JSON.stringify(ajv.errors, null, 2));
                        }
                        return lib.render(skinData, netlistData, cb);
                    }

                    var example = {
                        "creator": "Yosys 0.10.0 (git sha1 be9d50d, clang 6.0.0-1ubuntu2 -fPIC -Os)",
                        "modules": {
                            "Main": {
                                "attributes": {
                                    "cells_not_processed": "00000000000000000000000000000001",
                                    "src": "./example.v:25.1-44.10"
                                },
                                "ports": {
                                    "a": {
                                        "direction": "input",
                                        "bits": [2]
                                    },
                                    "b": {
                                        "direction": "input",
                                        "bits": [3]
                                    },
                                    "c": {
                                        "direction": "input",
                                        "bits": [4]
                                    },
                                    "Qus": {
                                        "direction": "output",
                                        "bits": [5]
                                    },
                                    "Qs": {
                                        "direction": "output",
                                        "bits": [6]
                                    }
                                },
                                "cells": {
                                    "simplified": {
                                        "hide_name": 0,
                                        "type": "Simplified",
                                        "parameters": {
                                        },
                                        "attributes": {
                                            "module_not_derived": "00000000000000000000000000000001",
                                            "src": "./example.v:37.14-42.4"
                                        },
                                        "port_directions": {
                                            "Q": "output",
                                            "a": "input",
                                            "b": "input",
                                            "c": "input"
                                        },
                                        "connections": {
                                            "Q": [6],
                                            "a": [2],
                                            "b": [3],
                                            "c": [4]
                                        }
                                    },
                                    "unsimplified": {
                                        "hide_name": 0,
                                        "type": "Unsimplified",
                                        "parameters": {
                                        },
                                        "attributes": {
                                            "module_not_derived": "00000000000000000000000000000001",
                                            "src": "./example.v:30.16-35.4"
                                        },
                                        "port_directions": {
                                            "Q": "output",
                                            "a": "input",
                                            "b": "input",
                                            "c": "input"
                                        },
                                        "connections": {
                                            "Q": [5],
                                            "a": [2],
                                            "b": [3],
                                            "c": [4]
                                        }
                                    }
                                },
                                "netnames": {
                                    "Qs": {
                                        "hide_name": 0,
                                        "bits": [6],
                                        "attributes": {
                                            "src": "./example.v:27.15-27.17"
                                        }
                                    },
                                    "Qus": {
                                        "hide_name": 0,
                                        "bits": [5],
                                        "attributes": {
                                            "src": "./example.v:27.10-27.13"
                                        }
                                    },
                                    "a": {
                                        "hide_name": 0,
                                        "bits": [2],
                                        "attributes": {
                                            "src": "./example.v:26.9-26.10"
                                        }
                                    },
                                    "b": {
                                        "hide_name": 0,
                                        "bits": [3],
                                        "attributes": {
                                            "src": "./example.v:26.12-26.13"
                                        }
                                    },
                                    "c": {
                                        "hide_name": 0,
                                        "bits": [4],
                                        "attributes": {
                                            "src": "./example.v:26.15-26.16"
                                        }
                                    }
                                }
                            },
                            "Simplified": {
                                "attributes": {
                                    "cells_not_processed": "00000000000000000000000000000001",
                                    "src": "./example.v:11.1-23.10"
                                },
                                "ports": {
                                    "a": {
                                        "direction": "input",
                                        "bits": [2]
                                    },
                                    "b": {
                                        "direction": "input",
                                        "bits": [3]
                                    },
                                    "c": {
                                        "direction": "input",
                                        "bits": [4]
                                    },
                                    "Q": {
                                        "direction": "output",
                                        "bits": [5]
                                    }
                                },
                                "cells": {
                                    "$and$./example.v:22$7": {
                                        "hide_name": 1,
                                        "type": "$and",
                                        "parameters": {
                                            "A_SIGNED": "00000000000000000000000000000000",
                                            "A_WIDTH": "00000000000000000000000000000001",
                                            "B_SIGNED": "00000000000000000000000000000000",
                                            "B_WIDTH": "00000000000000000000000000000001",
                                            "Y_WIDTH": "00000000000000000000000000000001"
                                        },
                                        "attributes": {
                                            "src": "./example.v:22.14-22.25"
                                        },
                                        "port_directions": {
                                            "A": "input",
                                            "B": "input",
                                            "Y": "output"
                                        },
                                        "connections": {
                                            "A": [3],
                                            "B": [6],
                                            "Y": [5]
                                        }
                                    },
                                    "$or$./example.v:22$6": {
                                        "hide_name": 1,
                                        "type": "$or",
                                        "parameters": {
                                            "A_SIGNED": "00000000000000000000000000000000",
                                            "A_WIDTH": "00000000000000000000000000000001",
                                            "B_SIGNED": "00000000000000000000000000000000",
                                            "B_WIDTH": "00000000000000000000000000000001",
                                            "Y_WIDTH": "00000000000000000000000000000001"
                                        },
                                        "attributes": {
                                            "src": "./example.v:22.19-22.24"
                                        },
                                        "port_directions": {
                                            "A": "input",
                                            "B": "input",
                                            "Y": "output"
                                        },
                                        "connections": {
                                            "A": [2],
                                            "B": [4],
                                            "Y": [6]
                                        }
                                    }
                                },
                                "netnames": {
                                    "$or$./example.v:22$6_Y": {
                                        "hide_name": 1,
                                        "bits": [6],
                                        "attributes": {
                                            "src": "./example.v:22.19-22.24"
                                        }
                                    },
                                    "Q": {
                                        "hide_name": 0,
                                        "bits": [5],
                                        "attributes": {
                                            "src": "./example.v:13.10-13.11"
                                        }
                                    },
                                    "a": {
                                        "hide_name": 0,
                                        "bits": [2],
                                        "attributes": {
                                            "src": "./example.v:12.9-12.10"
                                        }
                                    },
                                    "b": {
                                        "hide_name": 0,
                                        "bits": [3],
                                        "attributes": {
                                            "src": "./example.v:12.12-12.13"
                                        }
                                    },
                                    "c": {
                                        "hide_name": 0,
                                        "bits": [4],
                                        "attributes": {
                                            "src": "./example.v:12.15-12.16"
                                        }
                                    }
                                }
                            },
                            "Unsimplified": {
                                "attributes": {
                                    "cells_not_processed": "00000000000000000000000000000001",
                                    "src": "./example.v:4.1-9.10"
                                },
                                "ports": {
                                    "a": {
                                        "direction": "input",
                                        "bits": [2]
                                    },
                                    "b": {
                                        "direction": "input",
                                        "bits": [3]
                                    },
                                    "c": {
                                        "direction": "input",
                                        "bits": [4]
                                    },
                                    "Q": {
                                        "direction": "output",
                                        "bits": [5]
                                    }
                                },
                                "cells": {
                                    "$and$./example.v:8$1": {
                                        "hide_name": 1,
                                        "type": "$and",
                                        "parameters": {
                                            "A_SIGNED": "00000000000000000000000000000000",
                                            "A_WIDTH": "00000000000000000000000000000001",
                                            "B_SIGNED": "00000000000000000000000000000000",
                                            "B_WIDTH": "00000000000000000000000000000001",
                                            "Y_WIDTH": "00000000000000000000000000000001"
                                        },
                                        "attributes": {
                                            "src": "./example.v:8.14-8.19"
                                        },
                                        "port_directions": {
                                            "A": "input",
                                            "B": "input",
                                            "Y": "output"
                                        },
                                        "connections": {
                                            "A": [2],
                                            "B": [3],
                                            "Y": [6]
                                        }
                                    },
                                    "$and$./example.v:8$2": {
                                        "hide_name": 1,
                                        "type": "$and",
                                        "parameters": {
                                            "A_SIGNED": "00000000000000000000000000000000",
                                            "A_WIDTH": "00000000000000000000000000000001",
                                            "B_SIGNED": "00000000000000000000000000000000",
                                            "B_WIDTH": "00000000000000000000000000000001",
                                            "Y_WIDTH": "00000000000000000000000000000001"
                                        },
                                        "attributes": {
                                            "src": "./example.v:8.24-8.29"
                                        },
                                        "port_directions": {
                                            "A": "input",
                                            "B": "input",
                                            "Y": "output"
                                        },
                                        "connections": {
                                            "A": [3],
                                            "B": [4],
                                            "Y": [7]
                                        }
                                    },
                                    "$and$./example.v:8$4": {
                                        "hide_name": 1,
                                        "type": "$and",
                                        "parameters": {
                                            "A_SIGNED": "00000000000000000000000000000000",
                                            "A_WIDTH": "00000000000000000000000000000001",
                                            "B_SIGNED": "00000000000000000000000000000000",
                                            "B_WIDTH": "00000000000000000000000000000001",
                                            "Y_WIDTH": "00000000000000000000000000000001"
                                        },
                                        "attributes": {
                                            "src": "./example.v:8.23-8.40"
                                        },
                                        "port_directions": {
                                            "A": "input",
                                            "B": "input",
                                            "Y": "output"
                                        },
                                        "connections": {
                                            "A": [7],
                                            "B": [8],
                                            "Y": [9]
                                        }
                                    },
                                    "$or$./example.v:8$3": {
                                        "hide_name": 1,
                                        "type": "$or",
                                        "parameters": {
                                            "A_SIGNED": "00000000000000000000000000000000",
                                            "A_WIDTH": "00000000000000000000000000000001",
                                            "B_SIGNED": "00000000000000000000000000000000",
                                            "B_WIDTH": "00000000000000000000000000000001",
                                            "Y_WIDTH": "00000000000000000000000000000001"
                                        },
                                        "attributes": {
                                            "src": "./example.v:8.34-8.39"
                                        },
                                        "port_directions": {
                                            "A": "input",
                                            "B": "input",
                                            "Y": "output"
                                        },
                                        "connections": {
                                            "A": [3],
                                            "B": [4],
                                            "Y": [8]
                                        }
                                    },
                                    "$or$./example.v:8$5": {
                                        "hide_name": 1,
                                        "type": "$or",
                                        "parameters": {
                                            "A_SIGNED": "00000000000000000000000000000000",
                                            "A_WIDTH": "00000000000000000000000000000001",
                                            "B_SIGNED": "00000000000000000000000000000000",
                                            "B_WIDTH": "00000000000000000000000000000001",
                                            "Y_WIDTH": "00000000000000000000000000000001"
                                        },
                                        "attributes": {
                                            "src": "./example.v:8.14-8.41"
                                        },
                                        "port_directions": {
                                            "A": "input",
                                            "B": "input",
                                            "Y": "output"
                                        },
                                        "connections": {
                                            "A": [6],
                                            "B": [9],
                                            "Y": [5]
                                        }
                                    }
                                },
                                "netnames": {
                                    "$and$./example.v:8$1_Y": {
                                        "hide_name": 1,
                                        "bits": [6],
                                        "attributes": {
                                            "src": "./example.v:8.14-8.19"
                                        }
                                    },
                                    "$and$./example.v:8$2_Y": {
                                        "hide_name": 1,
                                        "bits": [7],
                                        "attributes": {
                                            "src": "./example.v:8.24-8.29"
                                        }
                                    },
                                    "$and$./example.v:8$4_Y": {
                                        "hide_name": 1,
                                        "bits": [9],
                                        "attributes": {
                                            "src": "./example.v:8.23-8.40"
                                        }
                                    },
                                    "$or$./example.v:8$3_Y": {
                                        "hide_name": 1,
                                        "bits": [8],
                                        "attributes": {
                                            "src": "./example.v:8.34-8.39"
                                        }
                                    },
                                    "Q": {
                                        "hide_name": 0,
                                        "bits": [5],
                                        "attributes": {
                                            "src": "./example.v:6.10-6.11"
                                        }
                                    },
                                    "a": {
                                        "hide_name": 0,
                                        "bits": [2],
                                        "attributes": {
                                            "src": "./example.v:5.9-5.10"
                                        }
                                    },
                                    "b": {
                                        "hide_name": 0,
                                        "bits": [3],
                                        "attributes": {
                                            "src": "./example.v:5.12-5.13"
                                        }
                                    },
                                    "c": {
                                        "hide_name": 0,
                                        "bits": [4],
                                        "attributes": {
                                            "src": "./example.v:5.15-5.16"
                                        }
                                    }
                                }
                            }
                        }
                    };

                    module.exports = {
                        render: render,
                        parser: lib.createFlatModule,
                        example: example,
                        digitalSkin: digital,
                        analogSkin: analog
                    };
                }).call(this)
            }).call(this, require("buffer").Buffer)
        }, { "../built": 33, "ajv": 36, "ajv-errors": 35, "buffer": 3, "json5": 101 }], 35: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const ajv_1 = require("ajv");
            const codegen_1 = require("ajv/dist/compile/codegen");
            const code_1 = require("ajv/dist/compile/codegen/code");
            const validate_1 = require("ajv/dist/compile/validate");
            const errors_1 = require("ajv/dist/compile/errors");
            const names_1 = require("ajv/dist/compile/names");
            const keyword = "errorMessage";
            const used = new ajv_1.Name("emUsed");
            const KEYWORD_PROPERTY_PARAMS = {
                required: "missingProperty",
                dependencies: "property",
                dependentRequired: "property",
            };
            const INTERPOLATION = /\$\{[^}]+\}/;
            const INTERPOLATION_REPLACE = /\$\{([^}]+)\}/g;
            const EMPTY_STR = /^""\s*\+\s*|\s*\+\s*""$/g;
            function errorMessage(options) {
                return {
                    keyword,
                    schemaType: ["string", "object"],
                    post: true,
                    code(cxt) {
                        const { gen, data, schema, schemaValue, it } = cxt;
                        if (it.createErrors === false)
                            return;
                        const sch = schema;
                        const instancePath = codegen_1.strConcat(names_1.default.instancePath, it.errorPath);
                        gen.if(ajv_1._`${names_1.default.errors} > 0`, () => {
                            if (typeof sch == "object") {
                                const [kwdPropErrors, kwdErrors] = keywordErrorsConfig(sch);
                                if (kwdErrors)
                                    processKeywordErrors(kwdErrors);
                                if (kwdPropErrors)
                                    processKeywordPropErrors(kwdPropErrors);
                                processChildErrors(childErrorsConfig(sch));
                            }
                            const schMessage = typeof sch == "string" ? sch : sch._;
                            if (schMessage)
                                processAllErrors(schMessage);
                            if (!options.keepErrors)
                                removeUsedErrors();
                        });
                        function childErrorsConfig({ properties, items }) {
                            const errors = {};
                            if (properties) {
                                errors.props = {};
                                for (const p in properties)
                                    errors.props[p] = [];
                            }
                            if (items) {
                                errors.items = {};
                                for (let i = 0; i < items.length; i++)
                                    errors.items[i] = [];
                            }
                            return errors;
                        }
                        function keywordErrorsConfig(emSchema) {
                            let propErrors;
                            let errors;
                            for (const k in emSchema) {
                                if (k === "properties" || k === "items")
                                    continue;
                                const kwdSch = emSchema[k];
                                if (typeof kwdSch == "object") {
                                    propErrors || (propErrors = {});
                                    const errMap = (propErrors[k] = {});
                                    for (const p in kwdSch)
                                        errMap[p] = [];
                                }
                                else {
                                    errors || (errors = {});
                                    errors[k] = [];
                                }
                            }
                            return [propErrors, errors];
                        }
                        function processKeywordErrors(kwdErrors) {
                            const kwdErrs = gen.const("emErrors", ajv_1.stringify(kwdErrors));
                            const templates = gen.const("templates", getTemplatesCode(kwdErrors, schema));
                            gen.forOf("err", names_1.default.vErrors, (err) => gen.if(matchKeywordError(err, kwdErrs), () => gen.code(ajv_1._`${kwdErrs}[${err}.keyword].push(${err})`).assign(ajv_1._`${err}.${used}`, true)));
                            const { singleError } = options;
                            if (singleError) {
                                const message = gen.let("message", ajv_1._`""`);
                                const paramsErrors = gen.let("paramsErrors", ajv_1._`[]`);
                                loopErrors((key) => {
                                    gen.if(message, () => gen.code(ajv_1._`${message} += ${typeof singleError == "string" ? singleError : ";"}`));
                                    gen.code(ajv_1._`${message} += ${errMessage(key)}`);
                                    gen.assign(paramsErrors, ajv_1._`${paramsErrors}.concat(${kwdErrs}[${key}])`);
                                });
                                errors_1.reportError(cxt, { message, params: ajv_1._`{errors: ${paramsErrors}}` });
                            }
                            else {
                                loopErrors((key) => errors_1.reportError(cxt, {
                                    message: errMessage(key),
                                    params: ajv_1._`{errors: ${kwdErrs}[${key}]}`,
                                }));
                            }
                            function loopErrors(body) {
                                gen.forIn("key", kwdErrs, (key) => gen.if(ajv_1._`${kwdErrs}[${key}].length`, () => body(key)));
                            }
                            function errMessage(key) {
                                return ajv_1._`${key} in ${templates} ? ${templates}[${key}]() : ${schemaValue}[${key}]`;
                            }
                        }
                        function processKeywordPropErrors(kwdPropErrors) {
                            const kwdErrs = gen.const("emErrors", ajv_1.stringify(kwdPropErrors));
                            const templatesCode = [];
                            for (const k in kwdPropErrors) {
                                templatesCode.push([
                                    k,
                                    getTemplatesCode(kwdPropErrors[k], schema[k]),
                                ]);
                            }
                            const templates = gen.const("templates", gen.object(...templatesCode));
                            const kwdPropParams = gen.scopeValue("obj", {
                                ref: KEYWORD_PROPERTY_PARAMS,
                                code: ajv_1.stringify(KEYWORD_PROPERTY_PARAMS),
                            });
                            const propParam = gen.let("emPropParams");
                            const paramsErrors = gen.let("emParamsErrors");
                            gen.forOf("err", names_1.default.vErrors, (err) => gen.if(matchKeywordError(err, kwdErrs), () => {
                                gen.assign(propParam, ajv_1._`${kwdPropParams}[${err}.keyword]`);
                                gen.assign(paramsErrors, ajv_1._`${kwdErrs}[${err}.keyword][${err}.params[${propParam}]]`);
                                gen.if(paramsErrors, () => gen.code(ajv_1._`${paramsErrors}.push(${err})`).assign(ajv_1._`${err}.${used}`, true));
                            }));
                            gen.forIn("key", kwdErrs, (key) => gen.forIn("keyProp", ajv_1._`${kwdErrs}[${key}]`, (keyProp) => {
                                gen.assign(paramsErrors, ajv_1._`${kwdErrs}[${key}][${keyProp}]`);
                                gen.if(ajv_1._`${paramsErrors}.length`, () => {
                                    const tmpl = gen.const("tmpl", ajv_1._`${templates}[${key}] && ${templates}[${key}][${keyProp}]`);
                                    errors_1.reportError(cxt, {
                                        message: ajv_1._`${tmpl} ? ${tmpl}() : ${schemaValue}[${key}][${keyProp}]`,
                                        params: ajv_1._`{errors: ${paramsErrors}}`,
                                    });
                                });
                            }));
                        }
                        function processChildErrors(childErrors) {
                            const { props, items } = childErrors;
                            if (!props && !items)
                                return;
                            const isObj = ajv_1._`typeof ${data} == "object"`;
                            const isArr = ajv_1._`Array.isArray(${data})`;
                            const childErrs = gen.let("emErrors");
                            let childKwd;
                            let childProp;
                            const templates = gen.let("templates");
                            if (props && items) {
                                childKwd = gen.let("emChildKwd");
                                gen.if(isObj);
                                gen.if(isArr, () => {
                                    init(items, schema.items);
                                    gen.assign(childKwd, ajv_1.str`items`);
                                }, () => {
                                    init(props, schema.properties);
                                    gen.assign(childKwd, ajv_1.str`properties`);
                                });
                                childProp = ajv_1._`[${childKwd}]`;
                            }
                            else if (items) {
                                gen.if(isArr);
                                init(items, schema.items);
                                childProp = ajv_1._`.items`;
                            }
                            else if (props) {
                                gen.if(codegen_1.and(isObj, codegen_1.not(isArr)));
                                init(props, schema.properties);
                                childProp = ajv_1._`.properties`;
                            }
                            gen.forOf("err", names_1.default.vErrors, (err) => ifMatchesChildError(err, childErrs, (child) => gen.code(ajv_1._`${childErrs}[${child}].push(${err})`).assign(ajv_1._`${err}.${used}`, true)));
                            gen.forIn("key", childErrs, (key) => gen.if(ajv_1._`${childErrs}[${key}].length`, () => {
                                errors_1.reportError(cxt, {
                                    message: ajv_1._`${key} in ${templates} ? ${templates}[${key}]() : ${schemaValue}${childProp}[${key}]`,
                                    params: ajv_1._`{errors: ${childErrs}[${key}]}`,
                                });
                                gen.assign(ajv_1._`${names_1.default.vErrors}[${names_1.default.errors}-1].instancePath`, ajv_1._`${instancePath} + "/" + ${key}.replace(/~/g, "~0").replace(/\\//g, "~1")`);
                            }));
                            gen.endIf();
                            function init(children, msgs) {
                                gen.assign(childErrs, ajv_1.stringify(children));
                                gen.assign(templates, getTemplatesCode(children, msgs));
                            }
                        }
                        function processAllErrors(schMessage) {
                            const errs = gen.const("emErrs", ajv_1._`[]`);
                            gen.forOf("err", names_1.default.vErrors, (err) => gen.if(matchAnyError(err), () => gen.code(ajv_1._`${errs}.push(${err})`).assign(ajv_1._`${err}.${used}`, true)));
                            gen.if(ajv_1._`${errs}.length`, () => errors_1.reportError(cxt, {
                                message: templateExpr(schMessage),
                                params: ajv_1._`{errors: ${errs}}`,
                            }));
                        }
                        function removeUsedErrors() {
                            const errs = gen.const("emErrs", ajv_1._`[]`);
                            gen.forOf("err", names_1.default.vErrors, (err) => gen.if(ajv_1._`!${err}.${used}`, () => gen.code(ajv_1._`${errs}.push(${err})`)));
                            gen.assign(names_1.default.vErrors, errs).assign(names_1.default.errors, ajv_1._`${errs}.length`);
                        }
                        function matchKeywordError(err, kwdErrs) {
                            return codegen_1.and(ajv_1._`${err}.keyword !== ${keyword}`, ajv_1._`!${err}.${used}`, ajv_1._`${err}.instancePath === ${instancePath}`, ajv_1._`${err}.keyword in ${kwdErrs}`,
                                // TODO match the end of the string?
                                ajv_1._`${err}.schemaPath.indexOf(${it.errSchemaPath}) === 0`, ajv_1._`/^\\/[^\\/]*$/.test(${err}.schemaPath.slice(${it.errSchemaPath.length}))`);
                        }
                        function ifMatchesChildError(err, childErrs, thenBody) {
                            gen.if(codegen_1.and(ajv_1._`${err}.keyword !== ${keyword}`, ajv_1._`!${err}.${used}`, ajv_1._`${err}.instancePath.indexOf(${instancePath}) === 0`), () => {
                                const childRegex = gen.scopeValue("pattern", {
                                    ref: /^\/([^/]*)(?:\/|$)/,
                                    code: ajv_1._`new RegExp("^\\\/([^/]*)(?:\\\/|$)")`,
                                });
                                const matches = gen.const("emMatches", ajv_1._`${childRegex}.exec(${err}.instancePath.slice(${instancePath}.length))`);
                                const child = gen.const("emChild", ajv_1._`${matches} && ${matches}[1].replace(/~1/g, "/").replace(/~0/g, "~")`);
                                gen.if(ajv_1._`${child} !== undefined && ${child} in ${childErrs}`, () => thenBody(child));
                            });
                        }
                        function matchAnyError(err) {
                            return codegen_1.and(ajv_1._`${err}.keyword !== ${keyword}`, ajv_1._`!${err}.${used}`, codegen_1.or(ajv_1._`${err}.instancePath === ${instancePath}`, codegen_1.and(ajv_1._`${err}.instancePath.indexOf(${instancePath}) === 0`, ajv_1._`${err}.instancePath[${instancePath}.length] === "/"`)), ajv_1._`${err}.schemaPath.indexOf(${it.errSchemaPath}) === 0`, ajv_1._`${err}.schemaPath[${it.errSchemaPath}.length] === "/"`);
                        }
                        function getTemplatesCode(keys, msgs) {
                            const templatesCode = [];
                            for (const k in keys) {
                                const msg = msgs[k];
                                if (INTERPOLATION.test(msg))
                                    templatesCode.push([k, templateFunc(msg)]);
                            }
                            return gen.object(...templatesCode);
                        }
                        function templateExpr(msg) {
                            if (!INTERPOLATION.test(msg))
                                return ajv_1.stringify(msg);
                            return new code_1._Code(code_1.safeStringify(msg)
                                .replace(INTERPOLATION_REPLACE, (_s, ptr) => `" + JSON.stringify(${validate_1.getData(ptr, it)}) + "`)
                                .replace(EMPTY_STR, ""));
                        }
                        function templateFunc(msg) {
                            return ajv_1._`function(){return ${templateExpr(msg)}}`;
                        }
                    },
                    metaSchema: {
                        anyOf: [
                            { type: "string" },
                            {
                                type: "object",
                                properties: {
                                    properties: { $ref: "#/$defs/stringMap" },
                                    items: { $ref: "#/$defs/stringList" },
                                    required: { $ref: "#/$defs/stringOrMap" },
                                    dependencies: { $ref: "#/$defs/stringOrMap" },
                                },
                                additionalProperties: { type: "string" },
                            },
                        ],
                        $defs: {
                            stringMap: {
                                type: "object",
                                additionalProperties: { type: "string" },
                            },
                            stringOrMap: {
                                anyOf: [{ type: "string" }, { $ref: "#/$defs/stringMap" }],
                            },
                            stringList: { type: "array", items: { type: "string" } },
                        },
                    },
                };
            }
            const ajvErrors = (ajv, options = {}) => {
                if (!ajv.opts.allErrors)
                    throw new Error("ajv-errors: Ajv option allErrors must be true");
                if (ajv.opts.jsPropertySyntax) {
                    throw new Error("ajv-errors: ajv option jsPropertySyntax is not supported");
                }
                return ajv.addKeyword(errorMessage(options));
            };
            exports.default = ajvErrors;
            module.exports = ajvErrors;
            module.exports.default = ajvErrors;

        }, { "ajv": 36, "ajv/dist/compile/codegen": 38, "ajv/dist/compile/codegen/code": 37, "ajv/dist/compile/errors": 40, "ajv/dist/compile/names": 42, "ajv/dist/compile/validate": 51 }], 36: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.CodeGen = exports.Name = exports.nil = exports.stringify = exports.str = exports._ = exports.KeywordCxt = void 0;
            const core_1 = require("./core");
            const draft7_1 = require("./vocabularies/draft7");
            const discriminator_1 = require("./vocabularies/discriminator");
            const draft7MetaSchema = require("./refs/json-schema-draft-07.json");
            const META_SUPPORT_DATA = ["/properties"];
            const META_SCHEMA_ID = "http://json-schema.org/draft-07/schema";
            class Ajv extends core_1.default {
                _addVocabularies() {
                    super._addVocabularies();
                    draft7_1.default.forEach((v) => this.addVocabulary(v));
                    if (this.opts.discriminator)
                        this.addKeyword(discriminator_1.default);
                }
                _addDefaultMetaSchema() {
                    super._addDefaultMetaSchema();
                    if (!this.opts.meta)
                        return;
                    const metaSchema = this.opts.$data
                        ? this.$dataMetaSchema(draft7MetaSchema, META_SUPPORT_DATA)
                        : draft7MetaSchema;
                    this.addMetaSchema(metaSchema, META_SCHEMA_ID, false);
                    this.refs["http://json-schema.org/schema"] = META_SCHEMA_ID;
                }
                defaultMeta() {
                    return (this.opts.defaultMeta =
                        super.defaultMeta() || (this.getSchema(META_SCHEMA_ID) ? META_SCHEMA_ID : undefined));
                }
            }
            module.exports = exports = Ajv;
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.default = Ajv;
            var validate_1 = require("./compile/validate");
            Object.defineProperty(exports, "KeywordCxt", { enumerable: true, get: function () { return validate_1.KeywordCxt; } });
            var codegen_1 = require("./compile/codegen");
            Object.defineProperty(exports, "_", { enumerable: true, get: function () { return codegen_1._; } });
            Object.defineProperty(exports, "str", { enumerable: true, get: function () { return codegen_1.str; } });
            Object.defineProperty(exports, "stringify", { enumerable: true, get: function () { return codegen_1.stringify; } });
            Object.defineProperty(exports, "nil", { enumerable: true, get: function () { return codegen_1.nil; } });
            Object.defineProperty(exports, "Name", { enumerable: true, get: function () { return codegen_1.Name; } });
            Object.defineProperty(exports, "CodeGen", { enumerable: true, get: function () { return codegen_1.CodeGen; } });

        }, { "./compile/codegen": 38, "./compile/validate": 51, "./core": 54, "./refs/json-schema-draft-07.json": 56, "./vocabularies/discriminator": 81, "./vocabularies/draft7": 83 }], 37: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.regexpCode = exports.getProperty = exports.safeStringify = exports.stringify = exports.strConcat = exports.addCodeArg = exports.str = exports._ = exports.nil = exports._Code = exports.Name = exports.IDENTIFIER = exports._CodeOrName = void 0;
            class _CodeOrName {
            }
            exports._CodeOrName = _CodeOrName;
            exports.IDENTIFIER = /^[a-z$_][a-z$_0-9]*$/i;
            class Name extends _CodeOrName {
                constructor(s) {
                    super();
                    if (!exports.IDENTIFIER.test(s))
                        throw new Error("CodeGen: name must be a valid identifier");
                    this.str = s;
                }
                toString() {
                    return this.str;
                }
                emptyStr() {
                    return false;
                }
                get names() {
                    return { [this.str]: 1 };
                }
            }
            exports.Name = Name;
            class _Code extends _CodeOrName {
                constructor(code) {
                    super();
                    this._items = typeof code === "string" ? [code] : code;
                }
                toString() {
                    return this.str;
                }
                emptyStr() {
                    if (this._items.length > 1)
                        return false;
                    const item = this._items[0];
                    return item === "" || item === '""';
                }
                get str() {
                    var _a;
                    return ((_a = this._str) !== null && _a !== void 0 ? _a : (this._str = this._items.reduce((s, c) => `${s}${c}`, "")));
                }
                get names() {
                    var _a;
                    return ((_a = this._names) !== null && _a !== void 0 ? _a : (this._names = this._items.reduce((names, c) => {
                        if (c instanceof Name)
                            names[c.str] = (names[c.str] || 0) + 1;
                        return names;
                    }, {})));
                }
            }
            exports._Code = _Code;
            exports.nil = new _Code("");
            function _(strs, ...args) {
                const code = [strs[0]];
                let i = 0;
                while (i < args.length) {
                    addCodeArg(code, args[i]);
                    code.push(strs[++i]);
                }
                return new _Code(code);
            }
            exports._ = _;
            const plus = new _Code("+");
            function str(strs, ...args) {
                const expr = [safeStringify(strs[0])];
                let i = 0;
                while (i < args.length) {
                    expr.push(plus);
                    addCodeArg(expr, args[i]);
                    expr.push(plus, safeStringify(strs[++i]));
                }
                optimize(expr);
                return new _Code(expr);
            }
            exports.str = str;
            function addCodeArg(code, arg) {
                if (arg instanceof _Code)
                    code.push(...arg._items);
                else if (arg instanceof Name)
                    code.push(arg);
                else
                    code.push(interpolate(arg));
            }
            exports.addCodeArg = addCodeArg;
            function optimize(expr) {
                let i = 1;
                while (i < expr.length - 1) {
                    if (expr[i] === plus) {
                        const res = mergeExprItems(expr[i - 1], expr[i + 1]);
                        if (res !== undefined) {
                            expr.splice(i - 1, 3, res);
                            continue;
                        }
                        expr[i++] = "+";
                    }
                    i++;
                }
            }
            function mergeExprItems(a, b) {
                if (b === '""')
                    return a;
                if (a === '""')
                    return b;
                if (typeof a == "string") {
                    if (b instanceof Name || a[a.length - 1] !== '"')
                        return;
                    if (typeof b != "string")
                        return `${a.slice(0, -1)}${b}"`;
                    if (b[0] === '"')
                        return a.slice(0, -1) + b.slice(1);
                    return;
                }
                if (typeof b == "string" && b[0] === '"' && !(a instanceof Name))
                    return `"${a}${b.slice(1)}`;
                return;
            }
            function strConcat(c1, c2) {
                return c2.emptyStr() ? c1 : c1.emptyStr() ? c2 : str`${c1}${c2}`;
            }
            exports.strConcat = strConcat;
            // TODO do not allow arrays here
            function interpolate(x) {
                return typeof x == "number" || typeof x == "boolean" || x === null
                    ? x
                    : safeStringify(Array.isArray(x) ? x.join(",") : x);
            }
            function stringify(x) {
                return new _Code(safeStringify(x));
            }
            exports.stringify = stringify;
            function safeStringify(x) {
                return JSON.stringify(x)
                    .replace(/\u2028/g, "\\u2028")
                    .replace(/\u2029/g, "\\u2029");
            }
            exports.safeStringify = safeStringify;
            function getProperty(key) {
                return typeof key == "string" && exports.IDENTIFIER.test(key) ? new _Code(`.${key}`) : _`[${key}]`;
            }
            exports.getProperty = getProperty;
            function regexpCode(rx) {
                return new _Code(rx.toString());
            }
            exports.regexpCode = regexpCode;

        }, {}], 38: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.or = exports.and = exports.not = exports.CodeGen = exports.operators = exports.varKinds = exports.ValueScopeName = exports.ValueScope = exports.Scope = exports.Name = exports.regexpCode = exports.stringify = exports.getProperty = exports.nil = exports.strConcat = exports.str = exports._ = void 0;
            const code_1 = require("./code");
            const scope_1 = require("./scope");
            var code_2 = require("./code");
            Object.defineProperty(exports, "_", { enumerable: true, get: function () { return code_2._; } });
            Object.defineProperty(exports, "str", { enumerable: true, get: function () { return code_2.str; } });
            Object.defineProperty(exports, "strConcat", { enumerable: true, get: function () { return code_2.strConcat; } });
            Object.defineProperty(exports, "nil", { enumerable: true, get: function () { return code_2.nil; } });
            Object.defineProperty(exports, "getProperty", { enumerable: true, get: function () { return code_2.getProperty; } });
            Object.defineProperty(exports, "stringify", { enumerable: true, get: function () { return code_2.stringify; } });
            Object.defineProperty(exports, "regexpCode", { enumerable: true, get: function () { return code_2.regexpCode; } });
            Object.defineProperty(exports, "Name", { enumerable: true, get: function () { return code_2.Name; } });
            var scope_2 = require("./scope");
            Object.defineProperty(exports, "Scope", { enumerable: true, get: function () { return scope_2.Scope; } });
            Object.defineProperty(exports, "ValueScope", { enumerable: true, get: function () { return scope_2.ValueScope; } });
            Object.defineProperty(exports, "ValueScopeName", { enumerable: true, get: function () { return scope_2.ValueScopeName; } });
            Object.defineProperty(exports, "varKinds", { enumerable: true, get: function () { return scope_2.varKinds; } });
            exports.operators = {
                GT: new code_1._Code(">"),
                GTE: new code_1._Code(">="),
                LT: new code_1._Code("<"),
                LTE: new code_1._Code("<="),
                EQ: new code_1._Code("==="),
                NEQ: new code_1._Code("!=="),
                NOT: new code_1._Code("!"),
                OR: new code_1._Code("||"),
                AND: new code_1._Code("&&"),
                ADD: new code_1._Code("+"),
            };
            class Node {
                optimizeNodes() {
                    return this;
                }
                optimizeNames(_names, _constants) {
                    return this;
                }
            }
            class Def extends Node {
                constructor(varKind, name, rhs) {
                    super();
                    this.varKind = varKind;
                    this.name = name;
                    this.rhs = rhs;
                }
                render({ es5, _n }) {
                    const varKind = es5 ? scope_1.varKinds.var : this.varKind;
                    const rhs = this.rhs === undefined ? "" : ` = ${this.rhs}`;
                    return `${varKind} ${this.name}${rhs};` + _n;
                }
                optimizeNames(names, constants) {
                    if (!names[this.name.str])
                        return;
                    if (this.rhs)
                        this.rhs = optimizeExpr(this.rhs, names, constants);
                    return this;
                }
                get names() {
                    return this.rhs instanceof code_1._CodeOrName ? this.rhs.names : {};
                }
            }
            class Assign extends Node {
                constructor(lhs, rhs, sideEffects) {
                    super();
                    this.lhs = lhs;
                    this.rhs = rhs;
                    this.sideEffects = sideEffects;
                }
                render({ _n }) {
                    return `${this.lhs} = ${this.rhs};` + _n;
                }
                optimizeNames(names, constants) {
                    if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
                        return;
                    this.rhs = optimizeExpr(this.rhs, names, constants);
                    return this;
                }
                get names() {
                    const names = this.lhs instanceof code_1.Name ? {} : { ...this.lhs.names };
                    return addExprNames(names, this.rhs);
                }
            }
            class AssignOp extends Assign {
                constructor(lhs, op, rhs, sideEffects) {
                    super(lhs, rhs, sideEffects);
                    this.op = op;
                }
                render({ _n }) {
                    return `${this.lhs} ${this.op}= ${this.rhs};` + _n;
                }
            }
            class Label extends Node {
                constructor(label) {
                    super();
                    this.label = label;
                    this.names = {};
                }
                render({ _n }) {
                    return `${this.label}:` + _n;
                }
            }
            class Break extends Node {
                constructor(label) {
                    super();
                    this.label = label;
                    this.names = {};
                }
                render({ _n }) {
                    const label = this.label ? ` ${this.label}` : "";
                    return `break${label};` + _n;
                }
            }
            class Throw extends Node {
                constructor(error) {
                    super();
                    this.error = error;
                }
                render({ _n }) {
                    return `throw ${this.error};` + _n;
                }
                get names() {
                    return this.error.names;
                }
            }
            class AnyCode extends Node {
                constructor(code) {
                    super();
                    this.code = code;
                }
                render({ _n }) {
                    return `${this.code};` + _n;
                }
                optimizeNodes() {
                    return `${this.code}` ? this : undefined;
                }
                optimizeNames(names, constants) {
                    this.code = optimizeExpr(this.code, names, constants);
                    return this;
                }
                get names() {
                    return this.code instanceof code_1._CodeOrName ? this.code.names : {};
                }
            }
            class ParentNode extends Node {
                constructor(nodes = []) {
                    super();
                    this.nodes = nodes;
                }
                render(opts) {
                    return this.nodes.reduce((code, n) => code + n.render(opts), "");
                }
                optimizeNodes() {
                    const { nodes } = this;
                    let i = nodes.length;
                    while (i--) {
                        const n = nodes[i].optimizeNodes();
                        if (Array.isArray(n))
                            nodes.splice(i, 1, ...n);
                        else if (n)
                            nodes[i] = n;
                        else
                            nodes.splice(i, 1);
                    }
                    return nodes.length > 0 ? this : undefined;
                }
                optimizeNames(names, constants) {
                    const { nodes } = this;
                    let i = nodes.length;
                    while (i--) {
                        // iterating backwards improves 1-pass optimization
                        const n = nodes[i];
                        if (n.optimizeNames(names, constants))
                            continue;
                        subtractNames(names, n.names);
                        nodes.splice(i, 1);
                    }
                    return nodes.length > 0 ? this : undefined;
                }
                get names() {
                    return this.nodes.reduce((names, n) => addNames(names, n.names), {});
                }
            }
            class BlockNode extends ParentNode {
                render(opts) {
                    return "{" + opts._n + super.render(opts) + "}" + opts._n;
                }
            }
            class Root extends ParentNode {
            }
            class Else extends BlockNode {
            }
            Else.kind = "else";
            class If extends BlockNode {
                constructor(condition, nodes) {
                    super(nodes);
                    this.condition = condition;
                }
                render(opts) {
                    let code = `if(${this.condition})` + super.render(opts);
                    if (this.else)
                        code += "else " + this.else.render(opts);
                    return code;
                }
                optimizeNodes() {
                    super.optimizeNodes();
                    const cond = this.condition;
                    if (cond === true)
                        return this.nodes; // else is ignored here
                    let e = this.else;
                    if (e) {
                        const ns = e.optimizeNodes();
                        e = this.else = Array.isArray(ns) ? new Else(ns) : ns;
                    }
                    if (e) {
                        if (cond === false)
                            return e instanceof If ? e : e.nodes;
                        if (this.nodes.length)
                            return this;
                        return new If(not(cond), e instanceof If ? [e] : e.nodes);
                    }
                    if (cond === false || !this.nodes.length)
                        return undefined;
                    return this;
                }
                optimizeNames(names, constants) {
                    var _a;
                    this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants);
                    if (!(super.optimizeNames(names, constants) || this.else))
                        return;
                    this.condition = optimizeExpr(this.condition, names, constants);
                    return this;
                }
                get names() {
                    const names = super.names;
                    addExprNames(names, this.condition);
                    if (this.else)
                        addNames(names, this.else.names);
                    return names;
                }
            }
            If.kind = "if";
            class For extends BlockNode {
            }
            For.kind = "for";
            class ForLoop extends For {
                constructor(iteration) {
                    super();
                    this.iteration = iteration;
                }
                render(opts) {
                    return `for(${this.iteration})` + super.render(opts);
                }
                optimizeNames(names, constants) {
                    if (!super.optimizeNames(names, constants))
                        return;
                    this.iteration = optimizeExpr(this.iteration, names, constants);
                    return this;
                }
                get names() {
                    return addNames(super.names, this.iteration.names);
                }
            }
            class ForRange extends For {
                constructor(varKind, name, from, to) {
                    super();
                    this.varKind = varKind;
                    this.name = name;
                    this.from = from;
                    this.to = to;
                }
                render(opts) {
                    const varKind = opts.es5 ? scope_1.varKinds.var : this.varKind;
                    const { name, from, to } = this;
                    return `for(${varKind} ${name}=${from}; ${name}<${to}; ${name}++)` + super.render(opts);
                }
                get names() {
                    const names = addExprNames(super.names, this.from);
                    return addExprNames(names, this.to);
                }
            }
            class ForIter extends For {
                constructor(loop, varKind, name, iterable) {
                    super();
                    this.loop = loop;
                    this.varKind = varKind;
                    this.name = name;
                    this.iterable = iterable;
                }
                render(opts) {
                    return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
                }
                optimizeNames(names, constants) {
                    if (!super.optimizeNames(names, constants))
                        return;
                    this.iterable = optimizeExpr(this.iterable, names, constants);
                    return this;
                }
                get names() {
                    return addNames(super.names, this.iterable.names);
                }
            }
            class Func extends BlockNode {
                constructor(name, args, async) {
                    super();
                    this.name = name;
                    this.args = args;
                    this.async = async;
                }
                render(opts) {
                    const _async = this.async ? "async " : "";
                    return `${_async}function ${this.name}(${this.args})` + super.render(opts);
                }
            }
            Func.kind = "func";
            class Return extends ParentNode {
                render(opts) {
                    return "return " + super.render(opts);
                }
            }
            Return.kind = "return";
            class Try extends BlockNode {
                render(opts) {
                    let code = "try" + super.render(opts);
                    if (this.catch)
                        code += this.catch.render(opts);
                    if (this.finally)
                        code += this.finally.render(opts);
                    return code;
                }
                optimizeNodes() {
                    var _a, _b;
                    super.optimizeNodes();
                    (_a = this.catch) === null || _a === void 0 ? void 0 : _a.optimizeNodes();
                    (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNodes();
                    return this;
                }
                optimizeNames(names, constants) {
                    var _a, _b;
                    super.optimizeNames(names, constants);
                    (_a = this.catch) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants);
                    (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants);
                    return this;
                }
                get names() {
                    const names = super.names;
                    if (this.catch)
                        addNames(names, this.catch.names);
                    if (this.finally)
                        addNames(names, this.finally.names);
                    return names;
                }
            }
            class Catch extends BlockNode {
                constructor(error) {
                    super();
                    this.error = error;
                }
                render(opts) {
                    return `catch(${this.error})` + super.render(opts);
                }
            }
            Catch.kind = "catch";
            class Finally extends BlockNode {
                render(opts) {
                    return "finally" + super.render(opts);
                }
            }
            Finally.kind = "finally";
            class CodeGen {
                constructor(extScope, opts = {}) {
                    this._values = {};
                    this._blockStarts = [];
                    this._constants = {};
                    this.opts = { ...opts, _n: opts.lines ? "\n" : "" };
                    this._extScope = extScope;
                    this._scope = new scope_1.Scope({ parent: extScope });
                    this._nodes = [new Root()];
                }
                toString() {
                    return this._root.render(this.opts);
                }
                // returns unique name in the internal scope
                name(prefix) {
                    return this._scope.name(prefix);
                }
                // reserves unique name in the external scope
                scopeName(prefix) {
                    return this._extScope.name(prefix);
                }
                // reserves unique name in the external scope and assigns value to it
                scopeValue(prefixOrName, value) {
                    const name = this._extScope.value(prefixOrName, value);
                    const vs = this._values[name.prefix] || (this._values[name.prefix] = new Set());
                    vs.add(name);
                    return name;
                }
                getScopeValue(prefix, keyOrRef) {
                    return this._extScope.getValue(prefix, keyOrRef);
                }
                // return code that assigns values in the external scope to the names that are used internally
                // (same names that were returned by gen.scopeName or gen.scopeValue)
                scopeRefs(scopeName) {
                    return this._extScope.scopeRefs(scopeName, this._values);
                }
                scopeCode() {
                    return this._extScope.scopeCode(this._values);
                }
                _def(varKind, nameOrPrefix, rhs, constant) {
                    const name = this._scope.toName(nameOrPrefix);
                    if (rhs !== undefined && constant)
                        this._constants[name.str] = rhs;
                    this._leafNode(new Def(varKind, name, rhs));
                    return name;
                }
                // `const` declaration (`var` in es5 mode)
                const(nameOrPrefix, rhs, _constant) {
                    return this._def(scope_1.varKinds.const, nameOrPrefix, rhs, _constant);
                }
                // `let` declaration with optional assignment (`var` in es5 mode)
                let(nameOrPrefix, rhs, _constant) {
                    return this._def(scope_1.varKinds.let, nameOrPrefix, rhs, _constant);
                }
                // `var` declaration with optional assignment
                var(nameOrPrefix, rhs, _constant) {
                    return this._def(scope_1.varKinds.var, nameOrPrefix, rhs, _constant);
                }
                // assignment code
                assign(lhs, rhs, sideEffects) {
                    return this._leafNode(new Assign(lhs, rhs, sideEffects));
                }
                // `+=` code
                add(lhs, rhs) {
                    return this._leafNode(new AssignOp(lhs, exports.operators.ADD, rhs));
                }
                // appends passed SafeExpr to code or executes Block
                code(c) {
                    if (typeof c == "function")
                        c();
                    else if (c !== code_1.nil)
                        this._leafNode(new AnyCode(c));
                    return this;
                }
                // returns code for object literal for the passed argument list of key-value pairs
                object(...keyValues) {
                    const code = ["{"];
                    for (const [key, value] of keyValues) {
                        if (code.length > 1)
                            code.push(",");
                        code.push(key);
                        if (key !== value || this.opts.es5) {
                            code.push(":");
                            (0, code_1.addCodeArg)(code, value);
                        }
                    }
                    code.push("}");
                    return new code_1._Code(code);
                }
                // `if` clause (or statement if `thenBody` and, optionally, `elseBody` are passed)
                if(condition, thenBody, elseBody) {
                    this._blockNode(new If(condition));
                    if (thenBody && elseBody) {
                        this.code(thenBody).else().code(elseBody).endIf();
                    }
                    else if (thenBody) {
                        this.code(thenBody).endIf();
                    }
                    else if (elseBody) {
                        throw new Error('CodeGen: "else" body without "then" body');
                    }
                    return this;
                }
                // `else if` clause - invalid without `if` or after `else` clauses
                elseIf(condition) {
                    return this._elseNode(new If(condition));
                }
                // `else` clause - only valid after `if` or `else if` clauses
                else() {
                    return this._elseNode(new Else());
                }
                // end `if` statement (needed if gen.if was used only with condition)
                endIf() {
                    return this._endBlockNode(If, Else);
                }
                _for(node, forBody) {
                    this._blockNode(node);
                    if (forBody)
                        this.code(forBody).endFor();
                    return this;
                }
                // a generic `for` clause (or statement if `forBody` is passed)
                for(iteration, forBody) {
                    return this._for(new ForLoop(iteration), forBody);
                }
                // `for` statement for a range of values
                forRange(nameOrPrefix, from, to, forBody, varKind = this.opts.es5 ? scope_1.varKinds.var : scope_1.varKinds.let) {
                    const name = this._scope.toName(nameOrPrefix);
                    return this._for(new ForRange(varKind, name, from, to), () => forBody(name));
                }
                // `for-of` statement (in es5 mode replace with a normal for loop)
                forOf(nameOrPrefix, iterable, forBody, varKind = scope_1.varKinds.const) {
                    const name = this._scope.toName(nameOrPrefix);
                    if (this.opts.es5) {
                        const arr = iterable instanceof code_1.Name ? iterable : this.var("_arr", iterable);
                        return this.forRange("_i", 0, (0, code_1._)`${arr}.length`, (i) => {
                            this.var(name, (0, code_1._)`${arr}[${i}]`);
                            forBody(name);
                        });
                    }
                    return this._for(new ForIter("of", varKind, name, iterable), () => forBody(name));
                }
                // `for-in` statement.
                // With option `ownProperties` replaced with a `for-of` loop for object keys
                forIn(nameOrPrefix, obj, forBody, varKind = this.opts.es5 ? scope_1.varKinds.var : scope_1.varKinds.const) {
                    if (this.opts.ownProperties) {
                        return this.forOf(nameOrPrefix, (0, code_1._)`Object.keys(${obj})`, forBody);
                    }
                    const name = this._scope.toName(nameOrPrefix);
                    return this._for(new ForIter("in", varKind, name, obj), () => forBody(name));
                }
                // end `for` loop
                endFor() {
                    return this._endBlockNode(For);
                }
                // `label` statement
                label(label) {
                    return this._leafNode(new Label(label));
                }
                // `break` statement
                break(label) {
                    return this._leafNode(new Break(label));
                }
                // `return` statement
                return(value) {
                    const node = new Return();
                    this._blockNode(node);
                    this.code(value);
                    if (node.nodes.length !== 1)
                        throw new Error('CodeGen: "return" should have one node');
                    return this._endBlockNode(Return);
                }
                // `try` statement
                try(tryBody, catchCode, finallyCode) {
                    if (!catchCode && !finallyCode)
                        throw new Error('CodeGen: "try" without "catch" and "finally"');
                    const node = new Try();
                    this._blockNode(node);
                    this.code(tryBody);
                    if (catchCode) {
                        const error = this.name("e");
                        this._currNode = node.catch = new Catch(error);
                        catchCode(error);
                    }
                    if (finallyCode) {
                        this._currNode = node.finally = new Finally();
                        this.code(finallyCode);
                    }
                    return this._endBlockNode(Catch, Finally);
                }
                // `throw` statement
                throw(error) {
                    return this._leafNode(new Throw(error));
                }
                // start self-balancing block
                block(body, nodeCount) {
                    this._blockStarts.push(this._nodes.length);
                    if (body)
                        this.code(body).endBlock(nodeCount);
                    return this;
                }
                // end the current self-balancing block
                endBlock(nodeCount) {
                    const len = this._blockStarts.pop();
                    if (len === undefined)
                        throw new Error("CodeGen: not in self-balancing block");
                    const toClose = this._nodes.length - len;
                    if (toClose < 0 || (nodeCount !== undefined && toClose !== nodeCount)) {
                        throw new Error(`CodeGen: wrong number of nodes: ${toClose} vs ${nodeCount} expected`);
                    }
                    this._nodes.length = len;
                    return this;
                }
                // `function` heading (or definition if funcBody is passed)
                func(name, args = code_1.nil, async, funcBody) {
                    this._blockNode(new Func(name, args, async));
                    if (funcBody)
                        this.code(funcBody).endFunc();
                    return this;
                }
                // end function definition
                endFunc() {
                    return this._endBlockNode(Func);
                }
                optimize(n = 1) {
                    while (n-- > 0) {
                        this._root.optimizeNodes();
                        this._root.optimizeNames(this._root.names, this._constants);
                    }
                }
                _leafNode(node) {
                    this._currNode.nodes.push(node);
                    return this;
                }
                _blockNode(node) {
                    this._currNode.nodes.push(node);
                    this._nodes.push(node);
                }
                _endBlockNode(N1, N2) {
                    const n = this._currNode;
                    if (n instanceof N1 || (N2 && n instanceof N2)) {
                        this._nodes.pop();
                        return this;
                    }
                    throw new Error(`CodeGen: not in block "${N2 ? `${N1.kind}/${N2.kind}` : N1.kind}"`);
                }
                _elseNode(node) {
                    const n = this._currNode;
                    if (!(n instanceof If)) {
                        throw new Error('CodeGen: "else" without "if"');
                    }
                    this._currNode = n.else = node;
                    return this;
                }
                get _root() {
                    return this._nodes[0];
                }
                get _currNode() {
                    const ns = this._nodes;
                    return ns[ns.length - 1];
                }
                set _currNode(node) {
                    const ns = this._nodes;
                    ns[ns.length - 1] = node;
                }
            }
            exports.CodeGen = CodeGen;
            function addNames(names, from) {
                for (const n in from)
                    names[n] = (names[n] || 0) + (from[n] || 0);
                return names;
            }
            function addExprNames(names, from) {
                return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
            }
            function optimizeExpr(expr, names, constants) {
                if (expr instanceof code_1.Name)
                    return replaceName(expr);
                if (!canOptimize(expr))
                    return expr;
                return new code_1._Code(expr._items.reduce((items, c) => {
                    if (c instanceof code_1.Name)
                        c = replaceName(c);
                    if (c instanceof code_1._Code)
                        items.push(...c._items);
                    else
                        items.push(c);
                    return items;
                }, []));
                function replaceName(n) {
                    const c = constants[n.str];
                    if (c === undefined || names[n.str] !== 1)
                        return n;
                    delete names[n.str];
                    return c;
                }
                function canOptimize(e) {
                    return (e instanceof code_1._Code &&
                        e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants[c.str] !== undefined));
                }
            }
            function subtractNames(names, from) {
                for (const n in from)
                    names[n] = (names[n] || 0) - (from[n] || 0);
            }
            function not(x) {
                return typeof x == "boolean" || typeof x == "number" || x === null ? !x : (0, code_1._)`!${par(x)}`;
            }
            exports.not = not;
            const andCode = mappend(exports.operators.AND);
            // boolean AND (&&) expression with the passed arguments
            function and(...args) {
                return args.reduce(andCode);
            }
            exports.and = and;
            const orCode = mappend(exports.operators.OR);
            // boolean OR (||) expression with the passed arguments
            function or(...args) {
                return args.reduce(orCode);
            }
            exports.or = or;
            function mappend(op) {
                return (x, y) => (x === code_1.nil ? y : y === code_1.nil ? x : (0, code_1._)`${par(x)} ${op} ${par(y)}`);
            }
            function par(x) {
                return x instanceof code_1.Name ? x : (0, code_1._)`(${x})`;
            }

        }, { "./code": 37, "./scope": 39 }], 39: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.ValueScope = exports.ValueScopeName = exports.Scope = exports.varKinds = exports.UsedValueState = void 0;
            const code_1 = require("./code");
            class ValueError extends Error {
                constructor(name) {
                    super(`CodeGen: "code" for ${name} not defined`);
                    this.value = name.value;
                }
            }
            var UsedValueState;
            (function (UsedValueState) {
                UsedValueState[UsedValueState["Started"] = 0] = "Started";
                UsedValueState[UsedValueState["Completed"] = 1] = "Completed";
            })(UsedValueState = exports.UsedValueState || (exports.UsedValueState = {}));
            exports.varKinds = {
                const: new code_1.Name("const"),
                let: new code_1.Name("let"),
                var: new code_1.Name("var"),
            };
            class Scope {
                constructor({ prefixes, parent } = {}) {
                    this._names = {};
                    this._prefixes = prefixes;
                    this._parent = parent;
                }
                toName(nameOrPrefix) {
                    return nameOrPrefix instanceof code_1.Name ? nameOrPrefix : this.name(nameOrPrefix);
                }
                name(prefix) {
                    return new code_1.Name(this._newName(prefix));
                }
                _newName(prefix) {
                    const ng = this._names[prefix] || this._nameGroup(prefix);
                    return `${prefix}${ng.index++}`;
                }
                _nameGroup(prefix) {
                    var _a, _b;
                    if (((_b = (_a = this._parent) === null || _a === void 0 ? void 0 : _a._prefixes) === null || _b === void 0 ? void 0 : _b.has(prefix)) || (this._prefixes && !this._prefixes.has(prefix))) {
                        throw new Error(`CodeGen: prefix "${prefix}" is not allowed in this scope`);
                    }
                    return (this._names[prefix] = { prefix, index: 0 });
                }
            }
            exports.Scope = Scope;
            class ValueScopeName extends code_1.Name {
                constructor(prefix, nameStr) {
                    super(nameStr);
                    this.prefix = prefix;
                }
                setValue(value, { property, itemIndex }) {
                    this.value = value;
                    this.scopePath = (0, code_1._)`.${new code_1.Name(property)}[${itemIndex}]`;
                }
            }
            exports.ValueScopeName = ValueScopeName;
            const line = (0, code_1._)`\n`;
            class ValueScope extends Scope {
                constructor(opts) {
                    super(opts);
                    this._values = {};
                    this._scope = opts.scope;
                    this.opts = { ...opts, _n: opts.lines ? line : code_1.nil };
                }
                get() {
                    return this._scope;
                }
                name(prefix) {
                    return new ValueScopeName(prefix, this._newName(prefix));
                }
                value(nameOrPrefix, value) {
                    var _a;
                    if (value.ref === undefined)
                        throw new Error("CodeGen: ref must be passed in value");
                    const name = this.toName(nameOrPrefix);
                    const { prefix } = name;
                    const valueKey = (_a = value.key) !== null && _a !== void 0 ? _a : value.ref;
                    let vs = this._values[prefix];
                    if (vs) {
                        const _name = vs.get(valueKey);
                        if (_name)
                            return _name;
                    }
                    else {
                        vs = this._values[prefix] = new Map();
                    }
                    vs.set(valueKey, name);
                    const s = this._scope[prefix] || (this._scope[prefix] = []);
                    const itemIndex = s.length;
                    s[itemIndex] = value.ref;
                    name.setValue(value, { property: prefix, itemIndex });
                    return name;
                }
                getValue(prefix, keyOrRef) {
                    const vs = this._values[prefix];
                    if (!vs)
                        return;
                    return vs.get(keyOrRef);
                }
                scopeRefs(scopeName, values = this._values) {
                    return this._reduceValues(values, (name) => {
                        if (name.scopePath === undefined)
                            throw new Error(`CodeGen: name "${name}" has no value`);
                        return (0, code_1._)`${scopeName}${name.scopePath}`;
                    });
                }
                scopeCode(values = this._values, usedValues, getCode) {
                    return this._reduceValues(values, (name) => {
                        if (name.value === undefined)
                            throw new Error(`CodeGen: name "${name}" has no value`);
                        return name.value.code;
                    }, usedValues, getCode);
                }
                _reduceValues(values, valueCode, usedValues = {}, getCode) {
                    let code = code_1.nil;
                    for (const prefix in values) {
                        const vs = values[prefix];
                        if (!vs)
                            continue;
                        const nameSet = (usedValues[prefix] = usedValues[prefix] || new Map());
                        vs.forEach((name) => {
                            if (nameSet.has(name))
                                return;
                            nameSet.set(name, UsedValueState.Started);
                            let c = valueCode(name);
                            if (c) {
                                const def = this.opts.es5 ? exports.varKinds.var : exports.varKinds.const;
                                code = (0, code_1._)`${code}${def} ${name} = ${c};${this.opts._n}`;
                            }
                            else if ((c = getCode === null || getCode === void 0 ? void 0 : getCode(name))) {
                                code = (0, code_1._)`${code}${c}${this.opts._n}`;
                            }
                            else {
                                throw new ValueError(name);
                            }
                            nameSet.set(name, UsedValueState.Completed);
                        });
                    }
                    return code;
                }
            }
            exports.ValueScope = ValueScope;

        }, { "./code": 37 }], 40: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.extendErrors = exports.resetErrorsCount = exports.reportExtraError = exports.reportError = exports.keyword$DataError = exports.keywordError = void 0;
            const codegen_1 = require("./codegen");
            const util_1 = require("./util");
            const names_1 = require("./names");
            exports.keywordError = {
                message: ({ keyword }) => (0, codegen_1.str)`must pass "${keyword}" keyword validation`,
            };
            exports.keyword$DataError = {
                message: ({ keyword, schemaType }) => schemaType
                    ? (0, codegen_1.str)`"${keyword}" keyword must be ${schemaType} ($data)`
                    : (0, codegen_1.str)`"${keyword}" keyword is invalid ($data)`,
            };
            function reportError(cxt, error = exports.keywordError, errorPaths, overrideAllErrors) {
                const { it } = cxt;
                const { gen, compositeRule, allErrors } = it;
                const errObj = errorObjectCode(cxt, error, errorPaths);
                if (overrideAllErrors !== null && overrideAllErrors !== void 0 ? overrideAllErrors : (compositeRule || allErrors)) {
                    addError(gen, errObj);
                }
                else {
                    returnErrors(it, (0, codegen_1._)`[${errObj}]`);
                }
            }
            exports.reportError = reportError;
            function reportExtraError(cxt, error = exports.keywordError, errorPaths) {
                const { it } = cxt;
                const { gen, compositeRule, allErrors } = it;
                const errObj = errorObjectCode(cxt, error, errorPaths);
                addError(gen, errObj);
                if (!(compositeRule || allErrors)) {
                    returnErrors(it, names_1.default.vErrors);
                }
            }
            exports.reportExtraError = reportExtraError;
            function resetErrorsCount(gen, errsCount) {
                gen.assign(names_1.default.errors, errsCount);
                gen.if((0, codegen_1._)`${names_1.default.vErrors} !== null`, () => gen.if(errsCount, () => gen.assign((0, codegen_1._)`${names_1.default.vErrors}.length`, errsCount), () => gen.assign(names_1.default.vErrors, null)));
            }
            exports.resetErrorsCount = resetErrorsCount;
            function extendErrors({ gen, keyword, schemaValue, data, errsCount, it, }) {
                /* istanbul ignore if */
                if (errsCount === undefined)
                    throw new Error("ajv implementation error");
                const err = gen.name("err");
                gen.forRange("i", errsCount, names_1.default.errors, (i) => {
                    gen.const(err, (0, codegen_1._)`${names_1.default.vErrors}[${i}]`);
                    gen.if((0, codegen_1._)`${err}.instancePath === undefined`, () => gen.assign((0, codegen_1._)`${err}.instancePath`, (0, codegen_1.strConcat)(names_1.default.instancePath, it.errorPath)));
                    gen.assign((0, codegen_1._)`${err}.schemaPath`, (0, codegen_1.str)`${it.errSchemaPath}/${keyword}`);
                    if (it.opts.verbose) {
                        gen.assign((0, codegen_1._)`${err}.schema`, schemaValue);
                        gen.assign((0, codegen_1._)`${err}.data`, data);
                    }
                });
            }
            exports.extendErrors = extendErrors;
            function addError(gen, errObj) {
                const err = gen.const("err", errObj);
                gen.if((0, codegen_1._)`${names_1.default.vErrors} === null`, () => gen.assign(names_1.default.vErrors, (0, codegen_1._)`[${err}]`), (0, codegen_1._)`${names_1.default.vErrors}.push(${err})`);
                gen.code((0, codegen_1._)`${names_1.default.errors}++`);
            }
            function returnErrors(it, errs) {
                const { gen, validateName, schemaEnv } = it;
                if (schemaEnv.$async) {
                    gen.throw((0, codegen_1._)`new ${it.ValidationError}(${errs})`);
                }
                else {
                    gen.assign((0, codegen_1._)`${validateName}.errors`, errs);
                    gen.return(false);
                }
            }
            const E = {
                keyword: new codegen_1.Name("keyword"),
                schemaPath: new codegen_1.Name("schemaPath"),
                params: new codegen_1.Name("params"),
                propertyName: new codegen_1.Name("propertyName"),
                message: new codegen_1.Name("message"),
                schema: new codegen_1.Name("schema"),
                parentSchema: new codegen_1.Name("parentSchema"),
            };
            function errorObjectCode(cxt, error, errorPaths) {
                const { createErrors } = cxt.it;
                if (createErrors === false)
                    return (0, codegen_1._)`{}`;
                return errorObject(cxt, error, errorPaths);
            }
            function errorObject(cxt, error, errorPaths = {}) {
                const { gen, it } = cxt;
                const keyValues = [
                    errorInstancePath(it, errorPaths),
                    errorSchemaPath(cxt, errorPaths),
                ];
                extraErrorProps(cxt, error, keyValues);
                return gen.object(...keyValues);
            }
            function errorInstancePath({ errorPath }, { instancePath }) {
                const instPath = instancePath
                    ? (0, codegen_1.str)`${errorPath}${(0, util_1.getErrorPath)(instancePath, util_1.Type.Str)}`
                    : errorPath;
                return [names_1.default.instancePath, (0, codegen_1.strConcat)(names_1.default.instancePath, instPath)];
            }
            function errorSchemaPath({ keyword, it: { errSchemaPath } }, { schemaPath, parentSchema }) {
                let schPath = parentSchema ? errSchemaPath : (0, codegen_1.str)`${errSchemaPath}/${keyword}`;
                if (schemaPath) {
                    schPath = (0, codegen_1.str)`${schPath}${(0, util_1.getErrorPath)(schemaPath, util_1.Type.Str)}`;
                }
                return [E.schemaPath, schPath];
            }
            function extraErrorProps(cxt, { params, message }, keyValues) {
                const { keyword, data, schemaValue, it } = cxt;
                const { opts, propertyName, topSchemaRef, schemaPath } = it;
                keyValues.push([E.keyword, keyword], [E.params, typeof params == "function" ? params(cxt) : params || (0, codegen_1._)`{}`]);
                if (opts.messages) {
                    keyValues.push([E.message, typeof message == "function" ? message(cxt) : message]);
                }
                if (opts.verbose) {
                    keyValues.push([E.schema, schemaValue], [E.parentSchema, (0, codegen_1._)`${topSchemaRef}${schemaPath}`], [names_1.default.data, data]);
                }
                if (propertyName)
                    keyValues.push([E.propertyName, propertyName]);
            }

        }, { "./codegen": 38, "./names": 42, "./util": 46 }], 41: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.resolveSchema = exports.getCompilingSchema = exports.resolveRef = exports.compileSchema = exports.SchemaEnv = void 0;
            const codegen_1 = require("./codegen");
            const validation_error_1 = require("../runtime/validation_error");
            const names_1 = require("./names");
            const resolve_1 = require("./resolve");
            const util_1 = require("./util");
            const validate_1 = require("./validate");
            const URI = require("uri-js");
            class SchemaEnv {
                constructor(env) {
                    var _a;
                    this.refs = {};
                    this.dynamicAnchors = {};
                    let schema;
                    if (typeof env.schema == "object")
                        schema = env.schema;
                    this.schema = env.schema;
                    this.schemaId = env.schemaId;
                    this.root = env.root || this;
                    this.baseId = (_a = env.baseId) !== null && _a !== void 0 ? _a : (0, resolve_1.normalizeId)(schema === null || schema === void 0 ? void 0 : schema[env.schemaId || "$id"]);
                    this.schemaPath = env.schemaPath;
                    this.localRefs = env.localRefs;
                    this.meta = env.meta;
                    this.$async = schema === null || schema === void 0 ? void 0 : schema.$async;
                    this.refs = {};
                }
            }
            exports.SchemaEnv = SchemaEnv;
            // let codeSize = 0
            // let nodeCount = 0
            // Compiles schema in SchemaEnv
            function compileSchema(sch) {
                // TODO refactor - remove compilations
                const _sch = getCompilingSchema.call(this, sch);
                if (_sch)
                    return _sch;
                const rootId = (0, resolve_1.getFullPath)(sch.root.baseId); // TODO if getFullPath removed 1 tests fails
                const { es5, lines } = this.opts.code;
                const { ownProperties } = this.opts;
                const gen = new codegen_1.CodeGen(this.scope, { es5, lines, ownProperties });
                let _ValidationError;
                if (sch.$async) {
                    _ValidationError = gen.scopeValue("Error", {
                        ref: validation_error_1.default,
                        code: (0, codegen_1._)`require("ajv/dist/runtime/validation_error").default`,
                    });
                }
                const validateName = gen.scopeName("validate");
                sch.validateName = validateName;
                const schemaCxt = {
                    gen,
                    allErrors: this.opts.allErrors,
                    data: names_1.default.data,
                    parentData: names_1.default.parentData,
                    parentDataProperty: names_1.default.parentDataProperty,
                    dataNames: [names_1.default.data],
                    dataPathArr: [codegen_1.nil],
                    dataLevel: 0,
                    dataTypes: [],
                    definedProperties: new Set(),
                    topSchemaRef: gen.scopeValue("schema", this.opts.code.source === true
                        ? { ref: sch.schema, code: (0, codegen_1.stringify)(sch.schema) }
                        : { ref: sch.schema }),
                    validateName,
                    ValidationError: _ValidationError,
                    schema: sch.schema,
                    schemaEnv: sch,
                    rootId,
                    baseId: sch.baseId || rootId,
                    schemaPath: codegen_1.nil,
                    errSchemaPath: sch.schemaPath || (this.opts.jtd ? "" : "#"),
                    errorPath: (0, codegen_1._)`""`,
                    opts: this.opts,
                    self: this,
                };
                let sourceCode;
                try {
                    this._compilations.add(sch);
                    (0, validate_1.validateFunctionCode)(schemaCxt);
                    gen.optimize(this.opts.code.optimize);
                    // gen.optimize(1)
                    const validateCode = gen.toString();
                    sourceCode = `${gen.scopeRefs(names_1.default.scope)}return ${validateCode}`;
                    // console.log((codeSize += sourceCode.length), (nodeCount += gen.nodeCount))
                    if (this.opts.code.process)
                        sourceCode = this.opts.code.process(sourceCode, sch);
                    // console.log("\n\n\n *** \n", sourceCode)
                    const makeValidate = new Function(`${names_1.default.self}`, `${names_1.default.scope}`, sourceCode);
                    const validate = makeValidate(this, this.scope.get());
                    this.scope.value(validateName, { ref: validate });
                    validate.errors = null;
                    validate.schema = sch.schema;
                    validate.schemaEnv = sch;
                    if (sch.$async)
                        validate.$async = true;
                    if (this.opts.code.source === true) {
                        validate.source = { validateName, validateCode, scopeValues: gen._values };
                    }
                    if (this.opts.unevaluated) {
                        const { props, items } = schemaCxt;
                        validate.evaluated = {
                            props: props instanceof codegen_1.Name ? undefined : props,
                            items: items instanceof codegen_1.Name ? undefined : items,
                            dynamicProps: props instanceof codegen_1.Name,
                            dynamicItems: items instanceof codegen_1.Name,
                        };
                        if (validate.source)
                            validate.source.evaluated = (0, codegen_1.stringify)(validate.evaluated);
                    }
                    sch.validate = validate;
                    return sch;
                }
                catch (e) {
                    delete sch.validate;
                    delete sch.validateName;
                    if (sourceCode)
                        this.logger.error("Error compiling schema, function code:", sourceCode);
                    // console.log("\n\n\n *** \n", sourceCode, this.opts)
                    throw e;
                }
                finally {
                    this._compilations.delete(sch);
                }
            }
            exports.compileSchema = compileSchema;
            function resolveRef(root, baseId, ref) {
                var _a;
                ref = (0, resolve_1.resolveUrl)(baseId, ref);
                const schOrFunc = root.refs[ref];
                if (schOrFunc)
                    return schOrFunc;
                let _sch = resolve.call(this, root, ref);
                if (_sch === undefined) {
                    const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref]; // TODO maybe localRefs should hold SchemaEnv
                    const { schemaId } = this.opts;
                    if (schema)
                        _sch = new SchemaEnv({ schema, schemaId, root, baseId });
                }
                if (_sch === undefined)
                    return;
                return (root.refs[ref] = inlineOrCompile.call(this, _sch));
            }
            exports.resolveRef = resolveRef;
            function inlineOrCompile(sch) {
                if ((0, resolve_1.inlineRef)(sch.schema, this.opts.inlineRefs))
                    return sch.schema;
                return sch.validate ? sch : compileSchema.call(this, sch);
            }
            // Index of schema compilation in the currently compiled list
            function getCompilingSchema(schEnv) {
                for (const sch of this._compilations) {
                    if (sameSchemaEnv(sch, schEnv))
                        return sch;
                }
            }
            exports.getCompilingSchema = getCompilingSchema;
            function sameSchemaEnv(s1, s2) {
                return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
            }
            // resolve and compile the references ($ref)
            // TODO returns AnySchemaObject (if the schema can be inlined) or validation function
            function resolve(root, // information about the root schema for the current schema
                ref // reference to resolve
            ) {
                let sch;
                while (typeof (sch = this.refs[ref]) == "string")
                    ref = sch;
                return sch || this.schemas[ref] || resolveSchema.call(this, root, ref);
            }
            // Resolve schema, its root and baseId
            function resolveSchema(root, // root object with properties schema, refs TODO below SchemaEnv is assigned to it
                ref // reference to resolve
            ) {
                const p = URI.parse(ref);
                const refPath = (0, resolve_1._getFullPath)(p);
                let baseId = (0, resolve_1.getFullPath)(root.baseId);
                // TODO `Object.keys(root.schema).length > 0` should not be needed - but removing breaks 2 tests
                if (Object.keys(root.schema).length > 0 && refPath === baseId) {
                    return getJsonPointer.call(this, p, root);
                }
                const id = (0, resolve_1.normalizeId)(refPath);
                const schOrRef = this.refs[id] || this.schemas[id];
                if (typeof schOrRef == "string") {
                    const sch = resolveSchema.call(this, root, schOrRef);
                    if (typeof (sch === null || sch === void 0 ? void 0 : sch.schema) !== "object")
                        return;
                    return getJsonPointer.call(this, p, sch);
                }
                if (typeof (schOrRef === null || schOrRef === void 0 ? void 0 : schOrRef.schema) !== "object")
                    return;
                if (!schOrRef.validate)
                    compileSchema.call(this, schOrRef);
                if (id === (0, resolve_1.normalizeId)(ref)) {
                    const { schema } = schOrRef;
                    const { schemaId } = this.opts;
                    const schId = schema[schemaId];
                    if (schId)
                        baseId = (0, resolve_1.resolveUrl)(baseId, schId);
                    return new SchemaEnv({ schema, schemaId, root, baseId });
                }
                return getJsonPointer.call(this, p, schOrRef);
            }
            exports.resolveSchema = resolveSchema;
            const PREVENT_SCOPE_CHANGE = new Set([
                "properties",
                "patternProperties",
                "enum",
                "dependencies",
                "definitions",
            ]);
            function getJsonPointer(parsedRef, { baseId, schema, root }) {
                var _a;
                if (((_a = parsedRef.fragment) === null || _a === void 0 ? void 0 : _a[0]) !== "/")
                    return;
                for (const part of parsedRef.fragment.slice(1).split("/")) {
                    if (typeof schema === "boolean")
                        return;
                    const partSchema = schema[(0, util_1.unescapeFragment)(part)];
                    if (partSchema === undefined)
                        return;
                    schema = partSchema;
                    // TODO PREVENT_SCOPE_CHANGE could be defined in keyword def?
                    const schId = typeof schema === "object" && schema[this.opts.schemaId];
                    if (!PREVENT_SCOPE_CHANGE.has(part) && schId) {
                        baseId = (0, resolve_1.resolveUrl)(baseId, schId);
                    }
                }
                let env;
                if (typeof schema != "boolean" && schema.$ref && !(0, util_1.schemaHasRulesButRef)(schema, this.RULES)) {
                    const $ref = (0, resolve_1.resolveUrl)(baseId, schema.$ref);
                    env = resolveSchema.call(this, root, $ref);
                }
                // even though resolution failed we need to return SchemaEnv to throw exception
                // so that compileAsync loads missing schema.
                const { schemaId } = this.opts;
                env = env || new SchemaEnv({ schema, schemaId, root, baseId });
                if (env.schema !== env.root.schema)
                    return env;
                return undefined;
            }

        }, { "../runtime/validation_error": 59, "./codegen": 38, "./names": 42, "./resolve": 44, "./util": 46, "./validate": 51, "uri-js": 111 }], 42: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("./codegen");
            const names = {
                // validation function arguments
                data: new codegen_1.Name("data"),
                // args passed from referencing schema
                valCxt: new codegen_1.Name("valCxt"),
                instancePath: new codegen_1.Name("instancePath"),
                parentData: new codegen_1.Name("parentData"),
                parentDataProperty: new codegen_1.Name("parentDataProperty"),
                rootData: new codegen_1.Name("rootData"),
                dynamicAnchors: new codegen_1.Name("dynamicAnchors"),
                // function scoped variables
                vErrors: new codegen_1.Name("vErrors"),
                errors: new codegen_1.Name("errors"),
                this: new codegen_1.Name("this"),
                // "globals"
                self: new codegen_1.Name("self"),
                scope: new codegen_1.Name("scope"),
                // JTD serialize/parse name for JSON string and position
                json: new codegen_1.Name("json"),
                jsonPos: new codegen_1.Name("jsonPos"),
                jsonLen: new codegen_1.Name("jsonLen"),
                jsonPart: new codegen_1.Name("jsonPart"),
            };
            exports.default = names;

        }, { "./codegen": 38 }], 43: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const resolve_1 = require("./resolve");
            class MissingRefError extends Error {
                constructor(baseId, ref, msg) {
                    super(msg || `can't resolve reference ${ref} from id ${baseId}`);
                    this.missingRef = (0, resolve_1.resolveUrl)(baseId, ref);
                    this.missingSchema = (0, resolve_1.normalizeId)((0, resolve_1.getFullPath)(this.missingRef));
                }
            }
            exports.default = MissingRefError;

        }, { "./resolve": 44 }], 44: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.getSchemaRefs = exports.resolveUrl = exports.normalizeId = exports._getFullPath = exports.getFullPath = exports.inlineRef = void 0;
            const util_1 = require("./util");
            const equal = require("fast-deep-equal");
            const traverse = require("json-schema-traverse");
            const URI = require("uri-js");
            // TODO refactor to use keyword definitions
            const SIMPLE_INLINED = new Set([
                "type",
                "format",
                "pattern",
                "maxLength",
                "minLength",
                "maxProperties",
                "minProperties",
                "maxItems",
                "minItems",
                "maximum",
                "minimum",
                "uniqueItems",
                "multipleOf",
                "required",
                "enum",
                "const",
            ]);
            function inlineRef(schema, limit = true) {
                if (typeof schema == "boolean")
                    return true;
                if (limit === true)
                    return !hasRef(schema);
                if (!limit)
                    return false;
                return countKeys(schema) <= limit;
            }
            exports.inlineRef = inlineRef;
            const REF_KEYWORDS = new Set([
                "$ref",
                "$recursiveRef",
                "$recursiveAnchor",
                "$dynamicRef",
                "$dynamicAnchor",
            ]);
            function hasRef(schema) {
                for (const key in schema) {
                    if (REF_KEYWORDS.has(key))
                        return true;
                    const sch = schema[key];
                    if (Array.isArray(sch) && sch.some(hasRef))
                        return true;
                    if (typeof sch == "object" && hasRef(sch))
                        return true;
                }
                return false;
            }
            function countKeys(schema) {
                let count = 0;
                for (const key in schema) {
                    if (key === "$ref")
                        return Infinity;
                    count++;
                    if (SIMPLE_INLINED.has(key))
                        continue;
                    if (typeof schema[key] == "object") {
                        (0, util_1.eachItem)(schema[key], (sch) => (count += countKeys(sch)));
                    }
                    if (count === Infinity)
                        return Infinity;
                }
                return count;
            }
            function getFullPath(id = "", normalize) {
                if (normalize !== false)
                    id = normalizeId(id);
                const p = URI.parse(id);
                return _getFullPath(p);
            }
            exports.getFullPath = getFullPath;
            function _getFullPath(p) {
                return URI.serialize(p).split("#")[0] + "#";
            }
            exports._getFullPath = _getFullPath;
            const TRAILING_SLASH_HASH = /#\/?$/;
            function normalizeId(id) {
                return id ? id.replace(TRAILING_SLASH_HASH, "") : "";
            }
            exports.normalizeId = normalizeId;
            function resolveUrl(baseId, id) {
                id = normalizeId(id);
                return URI.resolve(baseId, id);
            }
            exports.resolveUrl = resolveUrl;
            const ANCHOR = /^[a-z_][-a-z0-9._]*$/i;
            function getSchemaRefs(schema, baseId) {
                if (typeof schema == "boolean")
                    return {};
                const { schemaId } = this.opts;
                const schId = normalizeId(schema[schemaId] || baseId);
                const baseIds = { "": schId };
                const pathPrefix = getFullPath(schId, false);
                const localRefs = {};
                const schemaRefs = new Set();
                traverse(schema, { allKeys: true }, (sch, jsonPtr, _, parentJsonPtr) => {
                    if (parentJsonPtr === undefined)
                        return;
                    const fullPath = pathPrefix + jsonPtr;
                    let baseId = baseIds[parentJsonPtr];
                    if (typeof sch[schemaId] == "string")
                        baseId = addRef.call(this, sch[schemaId]);
                    addAnchor.call(this, sch.$anchor);
                    addAnchor.call(this, sch.$dynamicAnchor);
                    baseIds[jsonPtr] = baseId;
                    function addRef(ref) {
                        ref = normalizeId(baseId ? URI.resolve(baseId, ref) : ref);
                        if (schemaRefs.has(ref))
                            throw ambiguos(ref);
                        schemaRefs.add(ref);
                        let schOrRef = this.refs[ref];
                        if (typeof schOrRef == "string")
                            schOrRef = this.refs[schOrRef];
                        if (typeof schOrRef == "object") {
                            checkAmbiguosRef(sch, schOrRef.schema, ref);
                        }
                        else if (ref !== normalizeId(fullPath)) {
                            if (ref[0] === "#") {
                                checkAmbiguosRef(sch, localRefs[ref], ref);
                                localRefs[ref] = sch;
                            }
                            else {
                                this.refs[ref] = fullPath;
                            }
                        }
                        return ref;
                    }
                    function addAnchor(anchor) {
                        if (typeof anchor == "string") {
                            if (!ANCHOR.test(anchor))
                                throw new Error(`invalid anchor "${anchor}"`);
                            addRef.call(this, `#${anchor}`);
                        }
                    }
                });
                return localRefs;
                function checkAmbiguosRef(sch1, sch2, ref) {
                    if (sch2 !== undefined && !equal(sch1, sch2))
                        throw ambiguos(ref);
                }
                function ambiguos(ref) {
                    return new Error(`reference "${ref}" resolves to more than one schema`);
                }
            }
            exports.getSchemaRefs = getSchemaRefs;

        }, { "./util": 46, "fast-deep-equal": 99, "json-schema-traverse": 100, "uri-js": 111 }], 45: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.getRules = exports.isJSONType = void 0;
            const _jsonTypes = ["string", "number", "integer", "boolean", "null", "object", "array"];
            const jsonTypes = new Set(_jsonTypes);
            function isJSONType(x) {
                return typeof x == "string" && jsonTypes.has(x);
            }
            exports.isJSONType = isJSONType;
            function getRules() {
                const groups = {
                    number: { type: "number", rules: [] },
                    string: { type: "string", rules: [] },
                    array: { type: "array", rules: [] },
                    object: { type: "object", rules: [] },
                };
                return {
                    types: { ...groups, integer: true, boolean: true, null: true },
                    rules: [{ rules: [] }, groups.number, groups.string, groups.array, groups.object],
                    post: { rules: [] },
                    all: {},
                    keywords: {},
                };
            }
            exports.getRules = getRules;

        }, {}], 46: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.checkStrictMode = exports.getErrorPath = exports.Type = exports.useFunc = exports.setEvaluated = exports.evaluatedPropsToName = exports.mergeEvaluated = exports.eachItem = exports.unescapeJsonPointer = exports.escapeJsonPointer = exports.escapeFragment = exports.unescapeFragment = exports.schemaRefOrVal = exports.schemaHasRulesButRef = exports.schemaHasRules = exports.checkUnknownRules = exports.alwaysValidSchema = exports.toHash = void 0;
            const codegen_1 = require("./codegen");
            const code_1 = require("./codegen/code");
            // TODO refactor to use Set
            function toHash(arr) {
                const hash = {};
                for (const item of arr)
                    hash[item] = true;
                return hash;
            }
            exports.toHash = toHash;
            function alwaysValidSchema(it, schema) {
                if (typeof schema == "boolean")
                    return schema;
                if (Object.keys(schema).length === 0)
                    return true;
                checkUnknownRules(it, schema);
                return !schemaHasRules(schema, it.self.RULES.all);
            }
            exports.alwaysValidSchema = alwaysValidSchema;
            function checkUnknownRules(it, schema = it.schema) {
                const { opts, self } = it;
                if (!opts.strictSchema)
                    return;
                if (typeof schema === "boolean")
                    return;
                const rules = self.RULES.keywords;
                for (const key in schema) {
                    if (!rules[key])
                        checkStrictMode(it, `unknown keyword: "${key}"`);
                }
            }
            exports.checkUnknownRules = checkUnknownRules;
            function schemaHasRules(schema, rules) {
                if (typeof schema == "boolean")
                    return !schema;
                for (const key in schema)
                    if (rules[key])
                        return true;
                return false;
            }
            exports.schemaHasRules = schemaHasRules;
            function schemaHasRulesButRef(schema, RULES) {
                if (typeof schema == "boolean")
                    return !schema;
                for (const key in schema)
                    if (key !== "$ref" && RULES.all[key])
                        return true;
                return false;
            }
            exports.schemaHasRulesButRef = schemaHasRulesButRef;
            function schemaRefOrVal({ topSchemaRef, schemaPath }, schema, keyword, $data) {
                if (!$data) {
                    if (typeof schema == "number" || typeof schema == "boolean")
                        return schema;
                    if (typeof schema == "string")
                        return (0, codegen_1._)`${schema}`;
                }
                return (0, codegen_1._)`${topSchemaRef}${schemaPath}${(0, codegen_1.getProperty)(keyword)}`;
            }
            exports.schemaRefOrVal = schemaRefOrVal;
            function unescapeFragment(str) {
                return unescapeJsonPointer(decodeURIComponent(str));
            }
            exports.unescapeFragment = unescapeFragment;
            function escapeFragment(str) {
                return encodeURIComponent(escapeJsonPointer(str));
            }
            exports.escapeFragment = escapeFragment;
            function escapeJsonPointer(str) {
                if (typeof str == "number")
                    return `${str}`;
                return str.replace(/~/g, "~0").replace(/\//g, "~1");
            }
            exports.escapeJsonPointer = escapeJsonPointer;
            function unescapeJsonPointer(str) {
                return str.replace(/~1/g, "/").replace(/~0/g, "~");
            }
            exports.unescapeJsonPointer = unescapeJsonPointer;
            function eachItem(xs, f) {
                if (Array.isArray(xs)) {
                    for (const x of xs)
                        f(x);
                }
                else {
                    f(xs);
                }
            }
            exports.eachItem = eachItem;
            function makeMergeEvaluated({ mergeNames, mergeToName, mergeValues, resultToName, }) {
                return (gen, from, to, toName) => {
                    const res = to === undefined
                        ? from
                        : to instanceof codegen_1.Name
                            ? (from instanceof codegen_1.Name ? mergeNames(gen, from, to) : mergeToName(gen, from, to), to)
                            : from instanceof codegen_1.Name
                                ? (mergeToName(gen, to, from), from)
                                : mergeValues(from, to);
                    return toName === codegen_1.Name && !(res instanceof codegen_1.Name) ? resultToName(gen, res) : res;
                };
            }
            exports.mergeEvaluated = {
                props: makeMergeEvaluated({
                    mergeNames: (gen, from, to) => gen.if((0, codegen_1._)`${to} !== true && ${from} !== undefined`, () => {
                        gen.if((0, codegen_1._)`${from} === true`, () => gen.assign(to, true), () => gen.assign(to, (0, codegen_1._)`${to} || {}`).code((0, codegen_1._)`Object.assign(${to}, ${from})`));
                    }),
                    mergeToName: (gen, from, to) => gen.if((0, codegen_1._)`${to} !== true`, () => {
                        if (from === true) {
                            gen.assign(to, true);
                        }
                        else {
                            gen.assign(to, (0, codegen_1._)`${to} || {}`);
                            setEvaluated(gen, to, from);
                        }
                    }),
                    mergeValues: (from, to) => (from === true ? true : { ...from, ...to }),
                    resultToName: evaluatedPropsToName,
                }),
                items: makeMergeEvaluated({
                    mergeNames: (gen, from, to) => gen.if((0, codegen_1._)`${to} !== true && ${from} !== undefined`, () => gen.assign(to, (0, codegen_1._)`${from} === true ? true : ${to} > ${from} ? ${to} : ${from}`)),
                    mergeToName: (gen, from, to) => gen.if((0, codegen_1._)`${to} !== true`, () => gen.assign(to, from === true ? true : (0, codegen_1._)`${to} > ${from} ? ${to} : ${from}`)),
                    mergeValues: (from, to) => (from === true ? true : Math.max(from, to)),
                    resultToName: (gen, items) => gen.var("items", items),
                }),
            };
            function evaluatedPropsToName(gen, ps) {
                if (ps === true)
                    return gen.var("props", true);
                const props = gen.var("props", (0, codegen_1._)`{}`);
                if (ps !== undefined)
                    setEvaluated(gen, props, ps);
                return props;
            }
            exports.evaluatedPropsToName = evaluatedPropsToName;
            function setEvaluated(gen, props, ps) {
                Object.keys(ps).forEach((p) => gen.assign((0, codegen_1._)`${props}${(0, codegen_1.getProperty)(p)}`, true));
            }
            exports.setEvaluated = setEvaluated;
            const snippets = {};
            function useFunc(gen, f) {
                return gen.scopeValue("func", {
                    ref: f,
                    code: snippets[f.code] || (snippets[f.code] = new code_1._Code(f.code)),
                });
            }
            exports.useFunc = useFunc;
            var Type;
            (function (Type) {
                Type[Type["Num"] = 0] = "Num";
                Type[Type["Str"] = 1] = "Str";
            })(Type = exports.Type || (exports.Type = {}));
            function getErrorPath(dataProp, dataPropType, jsPropertySyntax) {
                // let path
                if (dataProp instanceof codegen_1.Name) {
                    const isNumber = dataPropType === Type.Num;
                    return jsPropertySyntax
                        ? isNumber
                            ? (0, codegen_1._)`"[" + ${dataProp} + "]"`
                            : (0, codegen_1._)`"['" + ${dataProp} + "']"`
                        : isNumber
                            ? (0, codegen_1._)`"/" + ${dataProp}`
                            : (0, codegen_1._)`"/" + ${dataProp}.replace(/~/g, "~0").replace(/\\//g, "~1")`; // TODO maybe use global escapePointer
                }
                return jsPropertySyntax ? (0, codegen_1.getProperty)(dataProp).toString() : "/" + escapeJsonPointer(dataProp);
            }
            exports.getErrorPath = getErrorPath;
            function checkStrictMode(it, msg, mode = it.opts.strictSchema) {
                if (!mode)
                    return;
                msg = `strict mode: ${msg}`;
                if (mode === true)
                    throw new Error(msg);
                it.self.logger.warn(msg);
            }
            exports.checkStrictMode = checkStrictMode;

        }, { "./codegen": 38, "./codegen/code": 37 }], 47: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.shouldUseRule = exports.shouldUseGroup = exports.schemaHasRulesForType = void 0;
            function schemaHasRulesForType({ schema, self }, type) {
                const group = self.RULES.types[type];
                return group && group !== true && shouldUseGroup(schema, group);
            }
            exports.schemaHasRulesForType = schemaHasRulesForType;
            function shouldUseGroup(schema, group) {
                return group.rules.some((rule) => shouldUseRule(schema, rule));
            }
            exports.shouldUseGroup = shouldUseGroup;
            function shouldUseRule(schema, rule) {
                var _a;
                return (schema[rule.keyword] !== undefined ||
                    ((_a = rule.definition.implements) === null || _a === void 0 ? void 0 : _a.some((kwd) => schema[kwd] !== undefined)));
            }
            exports.shouldUseRule = shouldUseRule;

        }, {}], 48: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.boolOrEmptySchema = exports.topBoolOrEmptySchema = void 0;
            const errors_1 = require("../errors");
            const codegen_1 = require("../codegen");
            const names_1 = require("../names");
            const boolError = {
                message: "boolean schema is false",
            };
            function topBoolOrEmptySchema(it) {
                const { gen, schema, validateName } = it;
                if (schema === false) {
                    falseSchemaError(it, false);
                }
                else if (typeof schema == "object" && schema.$async === true) {
                    gen.return(names_1.default.data);
                }
                else {
                    gen.assign((0, codegen_1._)`${validateName}.errors`, null);
                    gen.return(true);
                }
            }
            exports.topBoolOrEmptySchema = topBoolOrEmptySchema;
            function boolOrEmptySchema(it, valid) {
                const { gen, schema } = it;
                if (schema === false) {
                    gen.var(valid, false); // TODO var
                    falseSchemaError(it);
                }
                else {
                    gen.var(valid, true); // TODO var
                }
            }
            exports.boolOrEmptySchema = boolOrEmptySchema;
            function falseSchemaError(it, overrideAllErrors) {
                const { gen, data } = it;
                // TODO maybe some other interface should be used for non-keyword validation errors...
                const cxt = {
                    gen,
                    keyword: "false schema",
                    data,
                    schema: false,
                    schemaCode: false,
                    schemaValue: false,
                    params: {},
                    it,
                };
                (0, errors_1.reportError)(cxt, boolError, undefined, overrideAllErrors);
            }

        }, { "../codegen": 38, "../errors": 40, "../names": 42 }], 49: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.reportTypeError = exports.checkDataTypes = exports.checkDataType = exports.coerceAndCheckDataType = exports.getJSONTypes = exports.getSchemaTypes = exports.DataType = void 0;
            const rules_1 = require("../rules");
            const applicability_1 = require("./applicability");
            const errors_1 = require("../errors");
            const codegen_1 = require("../codegen");
            const util_1 = require("../util");
            var DataType;
            (function (DataType) {
                DataType[DataType["Correct"] = 0] = "Correct";
                DataType[DataType["Wrong"] = 1] = "Wrong";
            })(DataType = exports.DataType || (exports.DataType = {}));
            function getSchemaTypes(schema) {
                const types = getJSONTypes(schema.type);
                const hasNull = types.includes("null");
                if (hasNull) {
                    if (schema.nullable === false)
                        throw new Error("type: null contradicts nullable: false");
                }
                else {
                    if (!types.length && schema.nullable !== undefined) {
                        throw new Error('"nullable" cannot be used without "type"');
                    }
                    if (schema.nullable === true)
                        types.push("null");
                }
                return types;
            }
            exports.getSchemaTypes = getSchemaTypes;
            function getJSONTypes(ts) {
                const types = Array.isArray(ts) ? ts : ts ? [ts] : [];
                if (types.every(rules_1.isJSONType))
                    return types;
                throw new Error("type must be JSONType or JSONType[]: " + types.join(","));
            }
            exports.getJSONTypes = getJSONTypes;
            function coerceAndCheckDataType(it, types) {
                const { gen, data, opts } = it;
                const coerceTo = coerceToTypes(types, opts.coerceTypes);
                const checkTypes = types.length > 0 &&
                    !(coerceTo.length === 0 && types.length === 1 && (0, applicability_1.schemaHasRulesForType)(it, types[0]));
                if (checkTypes) {
                    const wrongType = checkDataTypes(types, data, opts.strictNumbers, DataType.Wrong);
                    gen.if(wrongType, () => {
                        if (coerceTo.length)
                            coerceData(it, types, coerceTo);
                        else
                            reportTypeError(it);
                    });
                }
                return checkTypes;
            }
            exports.coerceAndCheckDataType = coerceAndCheckDataType;
            const COERCIBLE = new Set(["string", "number", "integer", "boolean", "null"]);
            function coerceToTypes(types, coerceTypes) {
                return coerceTypes
                    ? types.filter((t) => COERCIBLE.has(t) || (coerceTypes === "array" && t === "array"))
                    : [];
            }
            function coerceData(it, types, coerceTo) {
                const { gen, data, opts } = it;
                const dataType = gen.let("dataType", (0, codegen_1._)`typeof ${data}`);
                const coerced = gen.let("coerced", (0, codegen_1._)`undefined`);
                if (opts.coerceTypes === "array") {
                    gen.if((0, codegen_1._)`${dataType} == 'object' && Array.isArray(${data}) && ${data}.length == 1`, () => gen
                        .assign(data, (0, codegen_1._)`${data}[0]`)
                        .assign(dataType, (0, codegen_1._)`typeof ${data}`)
                        .if(checkDataTypes(types, data, opts.strictNumbers), () => gen.assign(coerced, data)));
                }
                gen.if((0, codegen_1._)`${coerced} !== undefined`);
                for (const t of coerceTo) {
                    if (COERCIBLE.has(t) || (t === "array" && opts.coerceTypes === "array")) {
                        coerceSpecificType(t);
                    }
                }
                gen.else();
                reportTypeError(it);
                gen.endIf();
                gen.if((0, codegen_1._)`${coerced} !== undefined`, () => {
                    gen.assign(data, coerced);
                    assignParentData(it, coerced);
                });
                function coerceSpecificType(t) {
                    switch (t) {
                        case "string":
                            gen
                                .elseIf((0, codegen_1._)`${dataType} == "number" || ${dataType} == "boolean"`)
                                .assign(coerced, (0, codegen_1._)`"" + ${data}`)
                                .elseIf((0, codegen_1._)`${data} === null`)
                                .assign(coerced, (0, codegen_1._)`""`);
                            return;
                        case "number":
                            gen
                                .elseIf((0, codegen_1._)`${dataType} == "boolean" || ${data} === null
              || (${dataType} == "string" && ${data} && ${data} == +${data})`)
                                .assign(coerced, (0, codegen_1._)`+${data}`);
                            return;
                        case "integer":
                            gen
                                .elseIf((0, codegen_1._)`${dataType} === "boolean" || ${data} === null
              || (${dataType} === "string" && ${data} && ${data} == +${data} && !(${data} % 1))`)
                                .assign(coerced, (0, codegen_1._)`+${data}`);
                            return;
                        case "boolean":
                            gen
                                .elseIf((0, codegen_1._)`${data} === "false" || ${data} === 0 || ${data} === null`)
                                .assign(coerced, false)
                                .elseIf((0, codegen_1._)`${data} === "true" || ${data} === 1`)
                                .assign(coerced, true);
                            return;
                        case "null":
                            gen.elseIf((0, codegen_1._)`${data} === "" || ${data} === 0 || ${data} === false`);
                            gen.assign(coerced, null);
                            return;
                        case "array":
                            gen
                                .elseIf((0, codegen_1._)`${dataType} === "string" || ${dataType} === "number"
              || ${dataType} === "boolean" || ${data} === null`)
                                .assign(coerced, (0, codegen_1._)`[${data}]`);
                    }
                }
            }
            function assignParentData({ gen, parentData, parentDataProperty }, expr) {
                // TODO use gen.property
                gen.if((0, codegen_1._)`${parentData} !== undefined`, () => gen.assign((0, codegen_1._)`${parentData}[${parentDataProperty}]`, expr));
            }
            function checkDataType(dataType, data, strictNums, correct = DataType.Correct) {
                const EQ = correct === DataType.Correct ? codegen_1.operators.EQ : codegen_1.operators.NEQ;
                let cond;
                switch (dataType) {
                    case "null":
                        return (0, codegen_1._)`${data} ${EQ} null`;
                    case "array":
                        cond = (0, codegen_1._)`Array.isArray(${data})`;
                        break;
                    case "object":
                        cond = (0, codegen_1._)`${data} && typeof ${data} == "object" && !Array.isArray(${data})`;
                        break;
                    case "integer":
                        cond = numCond((0, codegen_1._)`!(${data} % 1) && !isNaN(${data})`);
                        break;
                    case "number":
                        cond = numCond();
                        break;
                    default:
                        return (0, codegen_1._)`typeof ${data} ${EQ} ${dataType}`;
                }
                return correct === DataType.Correct ? cond : (0, codegen_1.not)(cond);
                function numCond(_cond = codegen_1.nil) {
                    return (0, codegen_1.and)((0, codegen_1._)`typeof ${data} == "number"`, _cond, strictNums ? (0, codegen_1._)`isFinite(${data})` : codegen_1.nil);
                }
            }
            exports.checkDataType = checkDataType;
            function checkDataTypes(dataTypes, data, strictNums, correct) {
                if (dataTypes.length === 1) {
                    return checkDataType(dataTypes[0], data, strictNums, correct);
                }
                let cond;
                const types = (0, util_1.toHash)(dataTypes);
                if (types.array && types.object) {
                    const notObj = (0, codegen_1._)`typeof ${data} != "object"`;
                    cond = types.null ? notObj : (0, codegen_1._)`!${data} || ${notObj}`;
                    delete types.null;
                    delete types.array;
                    delete types.object;
                }
                else {
                    cond = codegen_1.nil;
                }
                if (types.number)
                    delete types.integer;
                for (const t in types)
                    cond = (0, codegen_1.and)(cond, checkDataType(t, data, strictNums, correct));
                return cond;
            }
            exports.checkDataTypes = checkDataTypes;
            const typeError = {
                message: ({ schema }) => `must be ${schema}`,
                params: ({ schema, schemaValue }) => typeof schema == "string" ? (0, codegen_1._)`{type: ${schema}}` : (0, codegen_1._)`{type: ${schemaValue}}`,
            };
            function reportTypeError(it) {
                const cxt = getTypeErrorContext(it);
                (0, errors_1.reportError)(cxt, typeError);
            }
            exports.reportTypeError = reportTypeError;
            function getTypeErrorContext(it) {
                const { gen, data, schema } = it;
                const schemaCode = (0, util_1.schemaRefOrVal)(it, schema, "type");
                return {
                    gen,
                    keyword: "type",
                    data,
                    schema: schema.type,
                    schemaCode,
                    schemaValue: schemaCode,
                    parentSchema: schema,
                    params: {},
                    it,
                };
            }

        }, { "../codegen": 38, "../errors": 40, "../rules": 45, "../util": 46, "./applicability": 47 }], 50: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.assignDefaults = void 0;
            const codegen_1 = require("../codegen");
            const util_1 = require("../util");
            function assignDefaults(it, ty) {
                const { properties, items } = it.schema;
                if (ty === "object" && properties) {
                    for (const key in properties) {
                        assignDefault(it, key, properties[key].default);
                    }
                }
                else if (ty === "array" && Array.isArray(items)) {
                    items.forEach((sch, i) => assignDefault(it, i, sch.default));
                }
            }
            exports.assignDefaults = assignDefaults;
            function assignDefault(it, prop, defaultValue) {
                const { gen, compositeRule, data, opts } = it;
                if (defaultValue === undefined)
                    return;
                const childData = (0, codegen_1._)`${data}${(0, codegen_1.getProperty)(prop)}`;
                if (compositeRule) {
                    (0, util_1.checkStrictMode)(it, `default is ignored for: ${childData}`);
                    return;
                }
                let condition = (0, codegen_1._)`${childData} === undefined`;
                if (opts.useDefaults === "empty") {
                    condition = (0, codegen_1._)`${condition} || ${childData} === null || ${childData} === ""`;
                }
                // `${childData} === undefined` +
                // (opts.useDefaults === "empty" ? ` || ${childData} === null || ${childData} === ""` : "")
                gen.if(condition, (0, codegen_1._)`${childData} = ${(0, codegen_1.stringify)(defaultValue)}`);
            }

        }, { "../codegen": 38, "../util": 46 }], 51: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.getData = exports.KeywordCxt = exports.validateFunctionCode = void 0;
            const boolSchema_1 = require("./boolSchema");
            const dataType_1 = require("./dataType");
            const applicability_1 = require("./applicability");
            const dataType_2 = require("./dataType");
            const defaults_1 = require("./defaults");
            const keyword_1 = require("./keyword");
            const subschema_1 = require("./subschema");
            const codegen_1 = require("../codegen");
            const names_1 = require("../names");
            const resolve_1 = require("../resolve");
            const util_1 = require("../util");
            const errors_1 = require("../errors");
            // schema compilation - generates validation function, subschemaCode (below) is used for subschemas
            function validateFunctionCode(it) {
                if (isSchemaObj(it)) {
                    checkKeywords(it);
                    if (schemaCxtHasRules(it)) {
                        topSchemaObjCode(it);
                        return;
                    }
                }
                validateFunction(it, () => (0, boolSchema_1.topBoolOrEmptySchema)(it));
            }
            exports.validateFunctionCode = validateFunctionCode;
            function validateFunction({ gen, validateName, schema, schemaEnv, opts }, body) {
                if (opts.code.es5) {
                    gen.func(validateName, (0, codegen_1._)`${names_1.default.data}, ${names_1.default.valCxt}`, schemaEnv.$async, () => {
                        gen.code((0, codegen_1._)`"use strict"; ${funcSourceUrl(schema, opts)}`);
                        destructureValCxtES5(gen, opts);
                        gen.code(body);
                    });
                }
                else {
                    gen.func(validateName, (0, codegen_1._)`${names_1.default.data}, ${destructureValCxt(opts)}`, schemaEnv.$async, () => gen.code(funcSourceUrl(schema, opts)).code(body));
                }
            }
            function destructureValCxt(opts) {
                return (0, codegen_1._)`{${names_1.default.instancePath}="", ${names_1.default.parentData}, ${names_1.default.parentDataProperty}, ${names_1.default.rootData}=${names_1.default.data}${opts.dynamicRef ? (0, codegen_1._)`, ${names_1.default.dynamicAnchors}={}` : codegen_1.nil}}={}`;
            }
            function destructureValCxtES5(gen, opts) {
                gen.if(names_1.default.valCxt, () => {
                    gen.var(names_1.default.instancePath, (0, codegen_1._)`${names_1.default.valCxt}.${names_1.default.instancePath}`);
                    gen.var(names_1.default.parentData, (0, codegen_1._)`${names_1.default.valCxt}.${names_1.default.parentData}`);
                    gen.var(names_1.default.parentDataProperty, (0, codegen_1._)`${names_1.default.valCxt}.${names_1.default.parentDataProperty}`);
                    gen.var(names_1.default.rootData, (0, codegen_1._)`${names_1.default.valCxt}.${names_1.default.rootData}`);
                    if (opts.dynamicRef)
                        gen.var(names_1.default.dynamicAnchors, (0, codegen_1._)`${names_1.default.valCxt}.${names_1.default.dynamicAnchors}`);
                }, () => {
                    gen.var(names_1.default.instancePath, (0, codegen_1._)`""`);
                    gen.var(names_1.default.parentData, (0, codegen_1._)`undefined`);
                    gen.var(names_1.default.parentDataProperty, (0, codegen_1._)`undefined`);
                    gen.var(names_1.default.rootData, names_1.default.data);
                    if (opts.dynamicRef)
                        gen.var(names_1.default.dynamicAnchors, (0, codegen_1._)`{}`);
                });
            }
            function topSchemaObjCode(it) {
                const { schema, opts, gen } = it;
                validateFunction(it, () => {
                    if (opts.$comment && schema.$comment)
                        commentKeyword(it);
                    checkNoDefault(it);
                    gen.let(names_1.default.vErrors, null);
                    gen.let(names_1.default.errors, 0);
                    if (opts.unevaluated)
                        resetEvaluated(it);
                    typeAndKeywords(it);
                    returnResults(it);
                });
                return;
            }
            function resetEvaluated(it) {
                // TODO maybe some hook to execute it in the end to check whether props/items are Name, as in assignEvaluated
                const { gen, validateName } = it;
                it.evaluated = gen.const("evaluated", (0, codegen_1._)`${validateName}.evaluated`);
                gen.if((0, codegen_1._)`${it.evaluated}.dynamicProps`, () => gen.assign((0, codegen_1._)`${it.evaluated}.props`, (0, codegen_1._)`undefined`));
                gen.if((0, codegen_1._)`${it.evaluated}.dynamicItems`, () => gen.assign((0, codegen_1._)`${it.evaluated}.items`, (0, codegen_1._)`undefined`));
            }
            function funcSourceUrl(schema, opts) {
                const schId = typeof schema == "object" && schema[opts.schemaId];
                return schId && (opts.code.source || opts.code.process) ? (0, codegen_1._)`/*# sourceURL=${schId} */` : codegen_1.nil;
            }
            // schema compilation - this function is used recursively to generate code for sub-schemas
            function subschemaCode(it, valid) {
                if (isSchemaObj(it)) {
                    checkKeywords(it);
                    if (schemaCxtHasRules(it)) {
                        subSchemaObjCode(it, valid);
                        return;
                    }
                }
                (0, boolSchema_1.boolOrEmptySchema)(it, valid);
            }
            function schemaCxtHasRules({ schema, self }) {
                if (typeof schema == "boolean")
                    return !schema;
                for (const key in schema)
                    if (self.RULES.all[key])
                        return true;
                return false;
            }
            function isSchemaObj(it) {
                return typeof it.schema != "boolean";
            }
            function subSchemaObjCode(it, valid) {
                const { schema, gen, opts } = it;
                if (opts.$comment && schema.$comment)
                    commentKeyword(it);
                updateContext(it);
                checkAsyncSchema(it);
                const errsCount = gen.const("_errs", names_1.default.errors);
                typeAndKeywords(it, errsCount);
                // TODO var
                gen.var(valid, (0, codegen_1._)`${errsCount} === ${names_1.default.errors}`);
            }
            function checkKeywords(it) {
                (0, util_1.checkUnknownRules)(it);
                checkRefsAndKeywords(it);
            }
            function typeAndKeywords(it, errsCount) {
                if (it.opts.jtd)
                    return schemaKeywords(it, [], false, errsCount);
                const types = (0, dataType_1.getSchemaTypes)(it.schema);
                const checkedTypes = (0, dataType_1.coerceAndCheckDataType)(it, types);
                schemaKeywords(it, types, !checkedTypes, errsCount);
            }
            function checkRefsAndKeywords(it) {
                const { schema, errSchemaPath, opts, self } = it;
                if (schema.$ref && opts.ignoreKeywordsWithRef && (0, util_1.schemaHasRulesButRef)(schema, self.RULES)) {
                    self.logger.warn(`$ref: keywords ignored in schema at path "${errSchemaPath}"`);
                }
            }
            function checkNoDefault(it) {
                const { schema, opts } = it;
                if (schema.default !== undefined && opts.useDefaults && opts.strictSchema) {
                    (0, util_1.checkStrictMode)(it, "default is ignored in the schema root");
                }
            }
            function updateContext(it) {
                const schId = it.schema[it.opts.schemaId];
                if (schId)
                    it.baseId = (0, resolve_1.resolveUrl)(it.baseId, schId);
            }
            function checkAsyncSchema(it) {
                if (it.schema.$async && !it.schemaEnv.$async)
                    throw new Error("async schema in sync schema");
            }
            function commentKeyword({ gen, schemaEnv, schema, errSchemaPath, opts }) {
                const msg = schema.$comment;
                if (opts.$comment === true) {
                    gen.code((0, codegen_1._)`${names_1.default.self}.logger.log(${msg})`);
                }
                else if (typeof opts.$comment == "function") {
                    const schemaPath = (0, codegen_1.str)`${errSchemaPath}/$comment`;
                    const rootName = gen.scopeValue("root", { ref: schemaEnv.root });
                    gen.code((0, codegen_1._)`${names_1.default.self}.opts.$comment(${msg}, ${schemaPath}, ${rootName}.schema)`);
                }
            }
            function returnResults(it) {
                const { gen, schemaEnv, validateName, ValidationError, opts } = it;
                if (schemaEnv.$async) {
                    // TODO assign unevaluated
                    gen.if((0, codegen_1._)`${names_1.default.errors} === 0`, () => gen.return(names_1.default.data), () => gen.throw((0, codegen_1._)`new ${ValidationError}(${names_1.default.vErrors})`));
                }
                else {
                    gen.assign((0, codegen_1._)`${validateName}.errors`, names_1.default.vErrors);
                    if (opts.unevaluated)
                        assignEvaluated(it);
                    gen.return((0, codegen_1._)`${names_1.default.errors} === 0`);
                }
            }
            function assignEvaluated({ gen, evaluated, props, items }) {
                if (props instanceof codegen_1.Name)
                    gen.assign((0, codegen_1._)`${evaluated}.props`, props);
                if (items instanceof codegen_1.Name)
                    gen.assign((0, codegen_1._)`${evaluated}.items`, items);
            }
            function schemaKeywords(it, types, typeErrors, errsCount) {
                const { gen, schema, data, allErrors, opts, self } = it;
                const { RULES } = self;
                if (schema.$ref && (opts.ignoreKeywordsWithRef || !(0, util_1.schemaHasRulesButRef)(schema, RULES))) {
                    gen.block(() => keywordCode(it, "$ref", RULES.all.$ref.definition)); // TODO typecast
                    return;
                }
                if (!opts.jtd)
                    checkStrictTypes(it, types);
                gen.block(() => {
                    for (const group of RULES.rules)
                        groupKeywords(group);
                    groupKeywords(RULES.post);
                });
                function groupKeywords(group) {
                    if (!(0, applicability_1.shouldUseGroup)(schema, group))
                        return;
                    if (group.type) {
                        gen.if((0, dataType_2.checkDataType)(group.type, data, opts.strictNumbers));
                        iterateKeywords(it, group);
                        if (types.length === 1 && types[0] === group.type && typeErrors) {
                            gen.else();
                            (0, dataType_2.reportTypeError)(it);
                        }
                        gen.endIf();
                    }
                    else {
                        iterateKeywords(it, group);
                    }
                    // TODO make it "ok" call?
                    if (!allErrors)
                        gen.if((0, codegen_1._)`${names_1.default.errors} === ${errsCount || 0}`);
                }
            }
            function iterateKeywords(it, group) {
                const { gen, schema, opts: { useDefaults }, } = it;
                if (useDefaults)
                    (0, defaults_1.assignDefaults)(it, group.type);
                gen.block(() => {
                    for (const rule of group.rules) {
                        if ((0, applicability_1.shouldUseRule)(schema, rule)) {
                            keywordCode(it, rule.keyword, rule.definition, group.type);
                        }
                    }
                });
            }
            function checkStrictTypes(it, types) {
                if (it.schemaEnv.meta || !it.opts.strictTypes)
                    return;
                checkContextTypes(it, types);
                if (!it.opts.allowUnionTypes)
                    checkMultipleTypes(it, types);
                checkKeywordTypes(it, it.dataTypes);
            }
            function checkContextTypes(it, types) {
                if (!types.length)
                    return;
                if (!it.dataTypes.length) {
                    it.dataTypes = types;
                    return;
                }
                types.forEach((t) => {
                    if (!includesType(it.dataTypes, t)) {
                        strictTypesError(it, `type "${t}" not allowed by context "${it.dataTypes.join(",")}"`);
                    }
                });
                it.dataTypes = it.dataTypes.filter((t) => includesType(types, t));
            }
            function checkMultipleTypes(it, ts) {
                if (ts.length > 1 && !(ts.length === 2 && ts.includes("null"))) {
                    strictTypesError(it, "use allowUnionTypes to allow union type keyword");
                }
            }
            function checkKeywordTypes(it, ts) {
                const rules = it.self.RULES.all;
                for (const keyword in rules) {
                    const rule = rules[keyword];
                    if (typeof rule == "object" && (0, applicability_1.shouldUseRule)(it.schema, rule)) {
                        const { type } = rule.definition;
                        if (type.length && !type.some((t) => hasApplicableType(ts, t))) {
                            strictTypesError(it, `missing type "${type.join(",")}" for keyword "${keyword}"`);
                        }
                    }
                }
            }
            function hasApplicableType(schTs, kwdT) {
                return schTs.includes(kwdT) || (kwdT === "number" && schTs.includes("integer"));
            }
            function includesType(ts, t) {
                return ts.includes(t) || (t === "integer" && ts.includes("number"));
            }
            function strictTypesError(it, msg) {
                const schemaPath = it.schemaEnv.baseId + it.errSchemaPath;
                msg += ` at "${schemaPath}" (strictTypes)`;
                (0, util_1.checkStrictMode)(it, msg, it.opts.strictTypes);
            }
            class KeywordCxt {
                constructor(it, def, keyword) {
                    (0, keyword_1.validateKeywordUsage)(it, def, keyword);
                    this.gen = it.gen;
                    this.allErrors = it.allErrors;
                    this.keyword = keyword;
                    this.data = it.data;
                    this.schema = it.schema[keyword];
                    this.$data = def.$data && it.opts.$data && this.schema && this.schema.$data;
                    this.schemaValue = (0, util_1.schemaRefOrVal)(it, this.schema, keyword, this.$data);
                    this.schemaType = def.schemaType;
                    this.parentSchema = it.schema;
                    this.params = {};
                    this.it = it;
                    this.def = def;
                    if (this.$data) {
                        this.schemaCode = it.gen.const("vSchema", getData(this.$data, it));
                    }
                    else {
                        this.schemaCode = this.schemaValue;
                        if (!(0, keyword_1.validSchemaType)(this.schema, def.schemaType, def.allowUndefined)) {
                            throw new Error(`${keyword} value must be ${JSON.stringify(def.schemaType)}`);
                        }
                    }
                    if ("code" in def ? def.trackErrors : def.errors !== false) {
                        this.errsCount = it.gen.const("_errs", names_1.default.errors);
                    }
                }
                result(condition, successAction, failAction) {
                    this.failResult((0, codegen_1.not)(condition), successAction, failAction);
                }
                failResult(condition, successAction, failAction) {
                    this.gen.if(condition);
                    if (failAction)
                        failAction();
                    else
                        this.error();
                    if (successAction) {
                        this.gen.else();
                        successAction();
                        if (this.allErrors)
                            this.gen.endIf();
                    }
                    else {
                        if (this.allErrors)
                            this.gen.endIf();
                        else
                            this.gen.else();
                    }
                }
                pass(condition, failAction) {
                    this.failResult((0, codegen_1.not)(condition), undefined, failAction);
                }
                fail(condition) {
                    if (condition === undefined) {
                        this.error();
                        if (!this.allErrors)
                            this.gen.if(false); // this branch will be removed by gen.optimize
                        return;
                    }
                    this.gen.if(condition);
                    this.error();
                    if (this.allErrors)
                        this.gen.endIf();
                    else
                        this.gen.else();
                }
                fail$data(condition) {
                    if (!this.$data)
                        return this.fail(condition);
                    const { schemaCode } = this;
                    this.fail((0, codegen_1._)`${schemaCode} !== undefined && (${(0, codegen_1.or)(this.invalid$data(), condition)})`);
                }
                error(append, errorParams, errorPaths) {
                    if (errorParams) {
                        this.setParams(errorParams);
                        this._error(append, errorPaths);
                        this.setParams({});
                        return;
                    }
                    this._error(append, errorPaths);
                }
                _error(append, errorPaths) {
                    ;
                    (append ? errors_1.reportExtraError : errors_1.reportError)(this, this.def.error, errorPaths);
                }
                $dataError() {
                    (0, errors_1.reportError)(this, this.def.$dataError || errors_1.keyword$DataError);
                }
                reset() {
                    if (this.errsCount === undefined)
                        throw new Error('add "trackErrors" to keyword definition');
                    (0, errors_1.resetErrorsCount)(this.gen, this.errsCount);
                }
                ok(cond) {
                    if (!this.allErrors)
                        this.gen.if(cond);
                }
                setParams(obj, assign) {
                    if (assign)
                        Object.assign(this.params, obj);
                    else
                        this.params = obj;
                }
                block$data(valid, codeBlock, $dataValid = codegen_1.nil) {
                    this.gen.block(() => {
                        this.check$data(valid, $dataValid);
                        codeBlock();
                    });
                }
                check$data(valid = codegen_1.nil, $dataValid = codegen_1.nil) {
                    if (!this.$data)
                        return;
                    const { gen, schemaCode, schemaType, def } = this;
                    gen.if((0, codegen_1.or)((0, codegen_1._)`${schemaCode} === undefined`, $dataValid));
                    if (valid !== codegen_1.nil)
                        gen.assign(valid, true);
                    if (schemaType.length || def.validateSchema) {
                        gen.elseIf(this.invalid$data());
                        this.$dataError();
                        if (valid !== codegen_1.nil)
                            gen.assign(valid, false);
                    }
                    gen.else();
                }
                invalid$data() {
                    const { gen, schemaCode, schemaType, def, it } = this;
                    return (0, codegen_1.or)(wrong$DataType(), invalid$DataSchema());
                    function wrong$DataType() {
                        if (schemaType.length) {
                            /* istanbul ignore if */
                            if (!(schemaCode instanceof codegen_1.Name))
                                throw new Error("ajv implementation error");
                            const st = Array.isArray(schemaType) ? schemaType : [schemaType];
                            return (0, codegen_1._)`${(0, dataType_2.checkDataTypes)(st, schemaCode, it.opts.strictNumbers, dataType_2.DataType.Wrong)}`;
                        }
                        return codegen_1.nil;
                    }
                    function invalid$DataSchema() {
                        if (def.validateSchema) {
                            const validateSchemaRef = gen.scopeValue("validate$data", { ref: def.validateSchema }); // TODO value.code for standalone
                            return (0, codegen_1._)`!${validateSchemaRef}(${schemaCode})`;
                        }
                        return codegen_1.nil;
                    }
                }
                subschema(appl, valid) {
                    const subschema = (0, subschema_1.getSubschema)(this.it, appl);
                    (0, subschema_1.extendSubschemaData)(subschema, this.it, appl);
                    (0, subschema_1.extendSubschemaMode)(subschema, appl);
                    const nextContext = { ...this.it, ...subschema, items: undefined, props: undefined };
                    subschemaCode(nextContext, valid);
                    return nextContext;
                }
                mergeEvaluated(schemaCxt, toName) {
                    const { it, gen } = this;
                    if (!it.opts.unevaluated)
                        return;
                    if (it.props !== true && schemaCxt.props !== undefined) {
                        it.props = util_1.mergeEvaluated.props(gen, schemaCxt.props, it.props, toName);
                    }
                    if (it.items !== true && schemaCxt.items !== undefined) {
                        it.items = util_1.mergeEvaluated.items(gen, schemaCxt.items, it.items, toName);
                    }
                }
                mergeValidEvaluated(schemaCxt, valid) {
                    const { it, gen } = this;
                    if (it.opts.unevaluated && (it.props !== true || it.items !== true)) {
                        gen.if(valid, () => this.mergeEvaluated(schemaCxt, codegen_1.Name));
                        return true;
                    }
                }
            }
            exports.KeywordCxt = KeywordCxt;
            function keywordCode(it, keyword, def, ruleType) {
                const cxt = new KeywordCxt(it, def, keyword);
                if ("code" in def) {
                    def.code(cxt, ruleType);
                }
                else if (cxt.$data && def.validate) {
                    (0, keyword_1.funcKeywordCode)(cxt, def);
                }
                else if ("macro" in def) {
                    (0, keyword_1.macroKeywordCode)(cxt, def);
                }
                else if (def.compile || def.validate) {
                    (0, keyword_1.funcKeywordCode)(cxt, def);
                }
            }
            const JSON_POINTER = /^\/(?:[^~]|~0|~1)*$/;
            const RELATIVE_JSON_POINTER = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/;
            function getData($data, { dataLevel, dataNames, dataPathArr }) {
                let jsonPointer;
                let data;
                if ($data === "")
                    return names_1.default.rootData;
                if ($data[0] === "/") {
                    if (!JSON_POINTER.test($data))
                        throw new Error(`Invalid JSON-pointer: ${$data}`);
                    jsonPointer = $data;
                    data = names_1.default.rootData;
                }
                else {
                    const matches = RELATIVE_JSON_POINTER.exec($data);
                    if (!matches)
                        throw new Error(`Invalid JSON-pointer: ${$data}`);
                    const up = +matches[1];
                    jsonPointer = matches[2];
                    if (jsonPointer === "#") {
                        if (up >= dataLevel)
                            throw new Error(errorMsg("property/index", up));
                        return dataPathArr[dataLevel - up];
                    }
                    if (up > dataLevel)
                        throw new Error(errorMsg("data", up));
                    data = dataNames[dataLevel - up];
                    if (!jsonPointer)
                        return data;
                }
                let expr = data;
                const segments = jsonPointer.split("/");
                for (const segment of segments) {
                    if (segment) {
                        data = (0, codegen_1._)`${data}${(0, codegen_1.getProperty)((0, util_1.unescapeJsonPointer)(segment))}`;
                        expr = (0, codegen_1._)`${expr} && ${data}`;
                    }
                }
                return expr;
                function errorMsg(pointerType, up) {
                    return `Cannot access ${pointerType} ${up} levels up, current level is ${dataLevel}`;
                }
            }
            exports.getData = getData;

        }, { "../codegen": 38, "../errors": 40, "../names": 42, "../resolve": 44, "../util": 46, "./applicability": 47, "./boolSchema": 48, "./dataType": 49, "./defaults": 50, "./keyword": 52, "./subschema": 53 }], 52: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.validateKeywordUsage = exports.validSchemaType = exports.funcKeywordCode = exports.macroKeywordCode = void 0;
            const codegen_1 = require("../codegen");
            const names_1 = require("../names");
            const code_1 = require("../../vocabularies/code");
            const errors_1 = require("../errors");
            function macroKeywordCode(cxt, def) {
                const { gen, keyword, schema, parentSchema, it } = cxt;
                const macroSchema = def.macro.call(it.self, schema, parentSchema, it);
                const schemaRef = useKeyword(gen, keyword, macroSchema);
                if (it.opts.validateSchema !== false)
                    it.self.validateSchema(macroSchema, true);
                const valid = gen.name("valid");
                cxt.subschema({
                    schema: macroSchema,
                    schemaPath: codegen_1.nil,
                    errSchemaPath: `${it.errSchemaPath}/${keyword}`,
                    topSchemaRef: schemaRef,
                    compositeRule: true,
                }, valid);
                cxt.pass(valid, () => cxt.error(true));
            }
            exports.macroKeywordCode = macroKeywordCode;
            function funcKeywordCode(cxt, def) {
                var _a;
                const { gen, keyword, schema, parentSchema, $data, it } = cxt;
                checkAsyncKeyword(it, def);
                const validate = !$data && def.compile ? def.compile.call(it.self, schema, parentSchema, it) : def.validate;
                const validateRef = useKeyword(gen, keyword, validate);
                const valid = gen.let("valid");
                cxt.block$data(valid, validateKeyword);
                cxt.ok((_a = def.valid) !== null && _a !== void 0 ? _a : valid);
                function validateKeyword() {
                    if (def.errors === false) {
                        assignValid();
                        if (def.modifying)
                            modifyData(cxt);
                        reportErrs(() => cxt.error());
                    }
                    else {
                        const ruleErrs = def.async ? validateAsync() : validateSync();
                        if (def.modifying)
                            modifyData(cxt);
                        reportErrs(() => addErrs(cxt, ruleErrs));
                    }
                }
                function validateAsync() {
                    const ruleErrs = gen.let("ruleErrs", null);
                    gen.try(() => assignValid((0, codegen_1._)`await `), (e) => gen.assign(valid, false).if((0, codegen_1._)`${e} instanceof ${it.ValidationError}`, () => gen.assign(ruleErrs, (0, codegen_1._)`${e}.errors`), () => gen.throw(e)));
                    return ruleErrs;
                }
                function validateSync() {
                    const validateErrs = (0, codegen_1._)`${validateRef}.errors`;
                    gen.assign(validateErrs, null);
                    assignValid(codegen_1.nil);
                    return validateErrs;
                }
                function assignValid(_await = def.async ? (0, codegen_1._)`await ` : codegen_1.nil) {
                    const passCxt = it.opts.passContext ? names_1.default.this : names_1.default.self;
                    const passSchema = !(("compile" in def && !$data) || def.schema === false);
                    gen.assign(valid, (0, codegen_1._)`${_await}${(0, code_1.callValidateCode)(cxt, validateRef, passCxt, passSchema)}`, def.modifying);
                }
                function reportErrs(errors) {
                    var _a;
                    gen.if((0, codegen_1.not)((_a = def.valid) !== null && _a !== void 0 ? _a : valid), errors);
                }
            }
            exports.funcKeywordCode = funcKeywordCode;
            function modifyData(cxt) {
                const { gen, data, it } = cxt;
                gen.if(it.parentData, () => gen.assign(data, (0, codegen_1._)`${it.parentData}[${it.parentDataProperty}]`));
            }
            function addErrs(cxt, errs) {
                const { gen } = cxt;
                gen.if((0, codegen_1._)`Array.isArray(${errs})`, () => {
                    gen
                        .assign(names_1.default.vErrors, (0, codegen_1._)`${names_1.default.vErrors} === null ? ${errs} : ${names_1.default.vErrors}.concat(${errs})`)
                        .assign(names_1.default.errors, (0, codegen_1._)`${names_1.default.vErrors}.length`);
                    (0, errors_1.extendErrors)(cxt);
                }, () => cxt.error());
            }
            function checkAsyncKeyword({ schemaEnv }, def) {
                if (def.async && !schemaEnv.$async)
                    throw new Error("async keyword in sync schema");
            }
            function useKeyword(gen, keyword, result) {
                if (result === undefined)
                    throw new Error(`keyword "${keyword}" failed to compile`);
                return gen.scopeValue("keyword", typeof result == "function" ? { ref: result } : { ref: result, code: (0, codegen_1.stringify)(result) });
            }
            function validSchemaType(schema, schemaType, allowUndefined = false) {
                // TODO add tests
                return (!schemaType.length ||
                    schemaType.some((st) => st === "array"
                        ? Array.isArray(schema)
                        : st === "object"
                            ? schema && typeof schema == "object" && !Array.isArray(schema)
                            : typeof schema == st || (allowUndefined && typeof schema == "undefined")));
            }
            exports.validSchemaType = validSchemaType;
            function validateKeywordUsage({ schema, opts, self, errSchemaPath }, def, keyword) {
                /* istanbul ignore if */
                if (Array.isArray(def.keyword) ? !def.keyword.includes(keyword) : def.keyword !== keyword) {
                    throw new Error("ajv implementation error");
                }
                const deps = def.dependencies;
                if (deps === null || deps === void 0 ? void 0 : deps.some((kwd) => !Object.prototype.hasOwnProperty.call(schema, kwd))) {
                    throw new Error(`parent schema must have dependencies of ${keyword}: ${deps.join(",")}`);
                }
                if (def.validateSchema) {
                    const valid = def.validateSchema(schema[keyword]);
                    if (!valid) {
                        const msg = `keyword "${keyword}" value is invalid at path "${errSchemaPath}": ` +
                            self.errorsText(def.validateSchema.errors);
                        if (opts.validateSchema === "log")
                            self.logger.error(msg);
                        else
                            throw new Error(msg);
                    }
                }
            }
            exports.validateKeywordUsage = validateKeywordUsage;

        }, { "../../vocabularies/code": 77, "../codegen": 38, "../errors": 40, "../names": 42 }], 53: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.extendSubschemaMode = exports.extendSubschemaData = exports.getSubschema = void 0;
            const codegen_1 = require("../codegen");
            const util_1 = require("../util");
            function getSubschema(it, { keyword, schemaProp, schema, schemaPath, errSchemaPath, topSchemaRef }) {
                if (keyword !== undefined && schema !== undefined) {
                    throw new Error('both "keyword" and "schema" passed, only one allowed');
                }
                if (keyword !== undefined) {
                    const sch = it.schema[keyword];
                    return schemaProp === undefined
                        ? {
                            schema: sch,
                            schemaPath: (0, codegen_1._)`${it.schemaPath}${(0, codegen_1.getProperty)(keyword)}`,
                            errSchemaPath: `${it.errSchemaPath}/${keyword}`,
                        }
                        : {
                            schema: sch[schemaProp],
                            schemaPath: (0, codegen_1._)`${it.schemaPath}${(0, codegen_1.getProperty)(keyword)}${(0, codegen_1.getProperty)(schemaProp)}`,
                            errSchemaPath: `${it.errSchemaPath}/${keyword}/${(0, util_1.escapeFragment)(schemaProp)}`,
                        };
                }
                if (schema !== undefined) {
                    if (schemaPath === undefined || errSchemaPath === undefined || topSchemaRef === undefined) {
                        throw new Error('"schemaPath", "errSchemaPath" and "topSchemaRef" are required with "schema"');
                    }
                    return {
                        schema,
                        schemaPath,
                        topSchemaRef,
                        errSchemaPath,
                    };
                }
                throw new Error('either "keyword" or "schema" must be passed');
            }
            exports.getSubschema = getSubschema;
            function extendSubschemaData(subschema, it, { dataProp, dataPropType: dpType, data, dataTypes, propertyName }) {
                if (data !== undefined && dataProp !== undefined) {
                    throw new Error('both "data" and "dataProp" passed, only one allowed');
                }
                const { gen } = it;
                if (dataProp !== undefined) {
                    const { errorPath, dataPathArr, opts } = it;
                    const nextData = gen.let("data", (0, codegen_1._)`${it.data}${(0, codegen_1.getProperty)(dataProp)}`, true);
                    dataContextProps(nextData);
                    subschema.errorPath = (0, codegen_1.str)`${errorPath}${(0, util_1.getErrorPath)(dataProp, dpType, opts.jsPropertySyntax)}`;
                    subschema.parentDataProperty = (0, codegen_1._)`${dataProp}`;
                    subschema.dataPathArr = [...dataPathArr, subschema.parentDataProperty];
                }
                if (data !== undefined) {
                    const nextData = data instanceof codegen_1.Name ? data : gen.let("data", data, true); // replaceable if used once?
                    dataContextProps(nextData);
                    if (propertyName !== undefined)
                        subschema.propertyName = propertyName;
                    // TODO something is possibly wrong here with not changing parentDataProperty and not appending dataPathArr
                }
                if (dataTypes)
                    subschema.dataTypes = dataTypes;
                function dataContextProps(_nextData) {
                    subschema.data = _nextData;
                    subschema.dataLevel = it.dataLevel + 1;
                    subschema.dataTypes = [];
                    it.definedProperties = new Set();
                    subschema.parentData = it.data;
                    subschema.dataNames = [...it.dataNames, _nextData];
                }
            }
            exports.extendSubschemaData = extendSubschemaData;
            function extendSubschemaMode(subschema, { jtdDiscriminator, jtdMetadata, compositeRule, createErrors, allErrors }) {
                if (compositeRule !== undefined)
                    subschema.compositeRule = compositeRule;
                if (createErrors !== undefined)
                    subschema.createErrors = createErrors;
                if (allErrors !== undefined)
                    subschema.allErrors = allErrors;
                subschema.jtdDiscriminator = jtdDiscriminator; // not inherited
                subschema.jtdMetadata = jtdMetadata; // not inherited
            }
            exports.extendSubschemaMode = extendSubschemaMode;

        }, { "../codegen": 38, "../util": 46 }], 54: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.CodeGen = exports.Name = exports.nil = exports.stringify = exports.str = exports._ = exports.KeywordCxt = void 0;
            var validate_1 = require("./compile/validate");
            Object.defineProperty(exports, "KeywordCxt", { enumerable: true, get: function () { return validate_1.KeywordCxt; } });
            var codegen_1 = require("./compile/codegen");
            Object.defineProperty(exports, "_", { enumerable: true, get: function () { return codegen_1._; } });
            Object.defineProperty(exports, "str", { enumerable: true, get: function () { return codegen_1.str; } });
            Object.defineProperty(exports, "stringify", { enumerable: true, get: function () { return codegen_1.stringify; } });
            Object.defineProperty(exports, "nil", { enumerable: true, get: function () { return codegen_1.nil; } });
            Object.defineProperty(exports, "Name", { enumerable: true, get: function () { return codegen_1.Name; } });
            Object.defineProperty(exports, "CodeGen", { enumerable: true, get: function () { return codegen_1.CodeGen; } });
            const validation_error_1 = require("./runtime/validation_error");
            const ref_error_1 = require("./compile/ref_error");
            const rules_1 = require("./compile/rules");
            const compile_1 = require("./compile");
            const codegen_2 = require("./compile/codegen");
            const resolve_1 = require("./compile/resolve");
            const dataType_1 = require("./compile/validate/dataType");
            const util_1 = require("./compile/util");
            const $dataRefSchema = require("./refs/data.json");
            const defaultRegExp = (str, flags) => new RegExp(str, flags);
            defaultRegExp.code = "new RegExp";
            const META_IGNORE_OPTIONS = ["removeAdditional", "useDefaults", "coerceTypes"];
            const EXT_SCOPE_NAMES = new Set([
                "validate",
                "serialize",
                "parse",
                "wrapper",
                "root",
                "schema",
                "keyword",
                "pattern",
                "formats",
                "validate$data",
                "func",
                "obj",
                "Error",
            ]);
            const removedOptions = {
                errorDataPath: "",
                format: "`validateFormats: false` can be used instead.",
                nullable: '"nullable" keyword is supported by default.',
                jsonPointers: "Deprecated jsPropertySyntax can be used instead.",
                extendRefs: "Deprecated ignoreKeywordsWithRef can be used instead.",
                missingRefs: "Pass empty schema with $id that should be ignored to ajv.addSchema.",
                processCode: "Use option `code: {process: (code, schemaEnv: object) => string}`",
                sourceCode: "Use option `code: {source: true}`",
                strictDefaults: "It is default now, see option `strict`.",
                strictKeywords: "It is default now, see option `strict`.",
                uniqueItems: '"uniqueItems" keyword is always validated.',
                unknownFormats: "Disable strict mode or pass `true` to `ajv.addFormat` (or `formats` option).",
                cache: "Map is used as cache, schema object as key.",
                serialize: "Map is used as cache, schema object as key.",
                ajvErrors: "It is default now.",
            };
            const deprecatedOptions = {
                ignoreKeywordsWithRef: "",
                jsPropertySyntax: "",
                unicode: '"minLength"/"maxLength" account for unicode characters by default.',
            };
            const MAX_EXPRESSION = 200;
            // eslint-disable-next-line complexity
            function requiredOptions(o) {
                var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
                const s = o.strict;
                const _optz = (_a = o.code) === null || _a === void 0 ? void 0 : _a.optimize;
                const optimize = _optz === true || _optz === undefined ? 1 : _optz || 0;
                const regExp = (_c = (_b = o.code) === null || _b === void 0 ? void 0 : _b.regExp) !== null && _c !== void 0 ? _c : defaultRegExp;
                return {
                    strictSchema: (_e = (_d = o.strictSchema) !== null && _d !== void 0 ? _d : s) !== null && _e !== void 0 ? _e : true,
                    strictNumbers: (_g = (_f = o.strictNumbers) !== null && _f !== void 0 ? _f : s) !== null && _g !== void 0 ? _g : true,
                    strictTypes: (_j = (_h = o.strictTypes) !== null && _h !== void 0 ? _h : s) !== null && _j !== void 0 ? _j : "log",
                    strictTuples: (_l = (_k = o.strictTuples) !== null && _k !== void 0 ? _k : s) !== null && _l !== void 0 ? _l : "log",
                    strictRequired: (_o = (_m = o.strictRequired) !== null && _m !== void 0 ? _m : s) !== null && _o !== void 0 ? _o : false,
                    code: o.code ? { ...o.code, optimize, regExp } : { optimize, regExp },
                    loopRequired: (_p = o.loopRequired) !== null && _p !== void 0 ? _p : MAX_EXPRESSION,
                    loopEnum: (_q = o.loopEnum) !== null && _q !== void 0 ? _q : MAX_EXPRESSION,
                    meta: (_r = o.meta) !== null && _r !== void 0 ? _r : true,
                    messages: (_s = o.messages) !== null && _s !== void 0 ? _s : true,
                    inlineRefs: (_t = o.inlineRefs) !== null && _t !== void 0 ? _t : true,
                    schemaId: (_u = o.schemaId) !== null && _u !== void 0 ? _u : "$id",
                    addUsedSchema: (_v = o.addUsedSchema) !== null && _v !== void 0 ? _v : true,
                    validateSchema: (_w = o.validateSchema) !== null && _w !== void 0 ? _w : true,
                    validateFormats: (_x = o.validateFormats) !== null && _x !== void 0 ? _x : true,
                    unicodeRegExp: (_y = o.unicodeRegExp) !== null && _y !== void 0 ? _y : true,
                    int32range: (_z = o.int32range) !== null && _z !== void 0 ? _z : true,
                };
            }
            class Ajv {
                constructor(opts = {}) {
                    this.schemas = {};
                    this.refs = {};
                    this.formats = {};
                    this._compilations = new Set();
                    this._loading = {};
                    this._cache = new Map();
                    opts = this.opts = { ...opts, ...requiredOptions(opts) };
                    const { es5, lines } = this.opts.code;
                    this.scope = new codegen_2.ValueScope({ scope: {}, prefixes: EXT_SCOPE_NAMES, es5, lines });
                    this.logger = getLogger(opts.logger);
                    const formatOpt = opts.validateFormats;
                    opts.validateFormats = false;
                    this.RULES = (0, rules_1.getRules)();
                    checkOptions.call(this, removedOptions, opts, "NOT SUPPORTED");
                    checkOptions.call(this, deprecatedOptions, opts, "DEPRECATED", "warn");
                    this._metaOpts = getMetaSchemaOptions.call(this);
                    if (opts.formats)
                        addInitialFormats.call(this);
                    this._addVocabularies();
                    this._addDefaultMetaSchema();
                    if (opts.keywords)
                        addInitialKeywords.call(this, opts.keywords);
                    if (typeof opts.meta == "object")
                        this.addMetaSchema(opts.meta);
                    addInitialSchemas.call(this);
                    opts.validateFormats = formatOpt;
                }
                _addVocabularies() {
                    this.addKeyword("$async");
                }
                _addDefaultMetaSchema() {
                    const { $data, meta, schemaId } = this.opts;
                    let _dataRefSchema = $dataRefSchema;
                    if (schemaId === "id") {
                        _dataRefSchema = { ...$dataRefSchema };
                        _dataRefSchema.id = _dataRefSchema.$id;
                        delete _dataRefSchema.$id;
                    }
                    if (meta && $data)
                        this.addMetaSchema(_dataRefSchema, _dataRefSchema[schemaId], false);
                }
                defaultMeta() {
                    const { meta, schemaId } = this.opts;
                    return (this.opts.defaultMeta = typeof meta == "object" ? meta[schemaId] || meta : undefined);
                }
                validate(schemaKeyRef, // key, ref or schema object
                    data // to be validated
                ) {
                    let v;
                    if (typeof schemaKeyRef == "string") {
                        v = this.getSchema(schemaKeyRef);
                        if (!v)
                            throw new Error(`no schema with key or ref "${schemaKeyRef}"`);
                    }
                    else {
                        v = this.compile(schemaKeyRef);
                    }
                    const valid = v(data);
                    if (!("$async" in v))
                        this.errors = v.errors;
                    return valid;
                }
                compile(schema, _meta) {
                    const sch = this._addSchema(schema, _meta);
                    return (sch.validate || this._compileSchemaEnv(sch));
                }
                compileAsync(schema, meta) {
                    if (typeof this.opts.loadSchema != "function") {
                        throw new Error("options.loadSchema should be a function");
                    }
                    const { loadSchema } = this.opts;
                    return runCompileAsync.call(this, schema, meta);
                    async function runCompileAsync(_schema, _meta) {
                        await loadMetaSchema.call(this, _schema.$schema);
                        const sch = this._addSchema(_schema, _meta);
                        return sch.validate || _compileAsync.call(this, sch);
                    }
                    async function loadMetaSchema($ref) {
                        if ($ref && !this.getSchema($ref)) {
                            await runCompileAsync.call(this, { $ref }, true);
                        }
                    }
                    async function _compileAsync(sch) {
                        try {
                            return this._compileSchemaEnv(sch);
                        }
                        catch (e) {
                            if (!(e instanceof ref_error_1.default))
                                throw e;
                            checkLoaded.call(this, e);
                            await loadMissingSchema.call(this, e.missingSchema);
                            return _compileAsync.call(this, sch);
                        }
                    }
                    function checkLoaded({ missingSchema: ref, missingRef }) {
                        if (this.refs[ref]) {
                            throw new Error(`AnySchema ${ref} is loaded but ${missingRef} cannot be resolved`);
                        }
                    }
                    async function loadMissingSchema(ref) {
                        const _schema = await _loadSchema.call(this, ref);
                        if (!this.refs[ref])
                            await loadMetaSchema.call(this, _schema.$schema);
                        if (!this.refs[ref])
                            this.addSchema(_schema, ref, meta);
                    }
                    async function _loadSchema(ref) {
                        const p = this._loading[ref];
                        if (p)
                            return p;
                        try {
                            return await (this._loading[ref] = loadSchema(ref));
                        }
                        finally {
                            delete this._loading[ref];
                        }
                    }
                }
                // Adds schema to the instance
                addSchema(schema, // If array is passed, `key` will be ignored
                    key, // Optional schema key. Can be passed to `validate` method instead of schema object or id/ref. One schema per instance can have empty `id` and `key`.
                    _meta, // true if schema is a meta-schema. Used internally, addMetaSchema should be used instead.
                    _validateSchema = this.opts.validateSchema // false to skip schema validation. Used internally, option validateSchema should be used instead.
                ) {
                    if (Array.isArray(schema)) {
                        for (const sch of schema)
                            this.addSchema(sch, undefined, _meta, _validateSchema);
                        return this;
                    }
                    let id;
                    if (typeof schema === "object") {
                        const { schemaId } = this.opts;
                        id = schema[schemaId];
                        if (id !== undefined && typeof id != "string") {
                            throw new Error(`schema ${schemaId} must be string`);
                        }
                    }
                    key = (0, resolve_1.normalizeId)(key || id);
                    this._checkUnique(key);
                    this.schemas[key] = this._addSchema(schema, _meta, key, _validateSchema, true);
                    return this;
                }
                // Add schema that will be used to validate other schemas
                // options in META_IGNORE_OPTIONS are alway set to false
                addMetaSchema(schema, key, // schema key
                    _validateSchema = this.opts.validateSchema // false to skip schema validation, can be used to override validateSchema option for meta-schema
                ) {
                    this.addSchema(schema, key, true, _validateSchema);
                    return this;
                }
                //  Validate schema against its meta-schema
                validateSchema(schema, throwOrLogError) {
                    if (typeof schema == "boolean")
                        return true;
                    let $schema;
                    $schema = schema.$schema;
                    if ($schema !== undefined && typeof $schema != "string") {
                        throw new Error("$schema must be a string");
                    }
                    $schema = $schema || this.opts.defaultMeta || this.defaultMeta();
                    if (!$schema) {
                        this.logger.warn("meta-schema not available");
                        this.errors = null;
                        return true;
                    }
                    const valid = this.validate($schema, schema);
                    if (!valid && throwOrLogError) {
                        const message = "schema is invalid: " + this.errorsText();
                        if (this.opts.validateSchema === "log")
                            this.logger.error(message);
                        else
                            throw new Error(message);
                    }
                    return valid;
                }
                // Get compiled schema by `key` or `ref`.
                // (`key` that was passed to `addSchema` or full schema reference - `schema.$id` or resolved id)
                getSchema(keyRef) {
                    let sch;
                    while (typeof (sch = getSchEnv.call(this, keyRef)) == "string")
                        keyRef = sch;
                    if (sch === undefined) {
                        const { schemaId } = this.opts;
                        const root = new compile_1.SchemaEnv({ schema: {}, schemaId });
                        sch = compile_1.resolveSchema.call(this, root, keyRef);
                        if (!sch)
                            return;
                        this.refs[keyRef] = sch;
                    }
                    return (sch.validate || this._compileSchemaEnv(sch));
                }
                // Remove cached schema(s).
                // If no parameter is passed all schemas but meta-schemas are removed.
                // If RegExp is passed all schemas with key/id matching pattern but meta-schemas are removed.
                // Even if schema is referenced by other schemas it still can be removed as other schemas have local references.
                removeSchema(schemaKeyRef) {
                    if (schemaKeyRef instanceof RegExp) {
                        this._removeAllSchemas(this.schemas, schemaKeyRef);
                        this._removeAllSchemas(this.refs, schemaKeyRef);
                        return this;
                    }
                    switch (typeof schemaKeyRef) {
                        case "undefined":
                            this._removeAllSchemas(this.schemas);
                            this._removeAllSchemas(this.refs);
                            this._cache.clear();
                            return this;
                        case "string": {
                            const sch = getSchEnv.call(this, schemaKeyRef);
                            if (typeof sch == "object")
                                this._cache.delete(sch.schema);
                            delete this.schemas[schemaKeyRef];
                            delete this.refs[schemaKeyRef];
                            return this;
                        }
                        case "object": {
                            const cacheKey = schemaKeyRef;
                            this._cache.delete(cacheKey);
                            let id = schemaKeyRef[this.opts.schemaId];
                            if (id) {
                                id = (0, resolve_1.normalizeId)(id);
                                delete this.schemas[id];
                                delete this.refs[id];
                            }
                            return this;
                        }
                        default:
                            throw new Error("ajv.removeSchema: invalid parameter");
                    }
                }
                // add "vocabulary" - a collection of keywords
                addVocabulary(definitions) {
                    for (const def of definitions)
                        this.addKeyword(def);
                    return this;
                }
                addKeyword(kwdOrDef, def // deprecated
                ) {
                    let keyword;
                    if (typeof kwdOrDef == "string") {
                        keyword = kwdOrDef;
                        if (typeof def == "object") {
                            this.logger.warn("these parameters are deprecated, see docs for addKeyword");
                            def.keyword = keyword;
                        }
                    }
                    else if (typeof kwdOrDef == "object" && def === undefined) {
                        def = kwdOrDef;
                        keyword = def.keyword;
                        if (Array.isArray(keyword) && !keyword.length) {
                            throw new Error("addKeywords: keyword must be string or non-empty array");
                        }
                    }
                    else {
                        throw new Error("invalid addKeywords parameters");
                    }
                    checkKeyword.call(this, keyword, def);
                    if (!def) {
                        (0, util_1.eachItem)(keyword, (kwd) => addRule.call(this, kwd));
                        return this;
                    }
                    keywordMetaschema.call(this, def);
                    const definition = {
                        ...def,
                        type: (0, dataType_1.getJSONTypes)(def.type),
                        schemaType: (0, dataType_1.getJSONTypes)(def.schemaType),
                    };
                    (0, util_1.eachItem)(keyword, definition.type.length === 0
                        ? (k) => addRule.call(this, k, definition)
                        : (k) => definition.type.forEach((t) => addRule.call(this, k, definition, t)));
                    return this;
                }
                getKeyword(keyword) {
                    const rule = this.RULES.all[keyword];
                    return typeof rule == "object" ? rule.definition : !!rule;
                }
                // Remove keyword
                removeKeyword(keyword) {
                    // TODO return type should be Ajv
                    const { RULES } = this;
                    delete RULES.keywords[keyword];
                    delete RULES.all[keyword];
                    for (const group of RULES.rules) {
                        const i = group.rules.findIndex((rule) => rule.keyword === keyword);
                        if (i >= 0)
                            group.rules.splice(i, 1);
                    }
                    return this;
                }
                // Add format
                addFormat(name, format) {
                    if (typeof format == "string")
                        format = new RegExp(format);
                    this.formats[name] = format;
                    return this;
                }
                errorsText(errors = this.errors, // optional array of validation errors
                    { separator = ", ", dataVar = "data" } = {} // optional options with properties `separator` and `dataVar`
                ) {
                    if (!errors || errors.length === 0)
                        return "No errors";
                    return errors
                        .map((e) => `${dataVar}${e.instancePath} ${e.message}`)
                        .reduce((text, msg) => text + separator + msg);
                }
                $dataMetaSchema(metaSchema, keywordsJsonPointers) {
                    const rules = this.RULES.all;
                    metaSchema = JSON.parse(JSON.stringify(metaSchema));
                    for (const jsonPointer of keywordsJsonPointers) {
                        const segments = jsonPointer.split("/").slice(1); // first segment is an empty string
                        let keywords = metaSchema;
                        for (const seg of segments)
                            keywords = keywords[seg];
                        for (const key in rules) {
                            const rule = rules[key];
                            if (typeof rule != "object")
                                continue;
                            const { $data } = rule.definition;
                            const schema = keywords[key];
                            if ($data && schema)
                                keywords[key] = schemaOrData(schema);
                        }
                    }
                    return metaSchema;
                }
                _removeAllSchemas(schemas, regex) {
                    for (const keyRef in schemas) {
                        const sch = schemas[keyRef];
                        if (!regex || regex.test(keyRef)) {
                            if (typeof sch == "string") {
                                delete schemas[keyRef];
                            }
                            else if (sch && !sch.meta) {
                                this._cache.delete(sch.schema);
                                delete schemas[keyRef];
                            }
                        }
                    }
                }
                _addSchema(schema, meta, baseId, validateSchema = this.opts.validateSchema, addSchema = this.opts.addUsedSchema) {
                    let id;
                    const { schemaId } = this.opts;
                    if (typeof schema == "object") {
                        id = schema[schemaId];
                    }
                    else {
                        if (this.opts.jtd)
                            throw new Error("schema must be object");
                        else if (typeof schema != "boolean")
                            throw new Error("schema must be object or boolean");
                    }
                    let sch = this._cache.get(schema);
                    if (sch !== undefined)
                        return sch;
                    baseId = (0, resolve_1.normalizeId)(id || baseId);
                    const localRefs = resolve_1.getSchemaRefs.call(this, schema, baseId);
                    sch = new compile_1.SchemaEnv({ schema, schemaId, meta, baseId, localRefs });
                    this._cache.set(sch.schema, sch);
                    if (addSchema && !baseId.startsWith("#")) {
                        // TODO atm it is allowed to overwrite schemas without id (instead of not adding them)
                        if (baseId)
                            this._checkUnique(baseId);
                        this.refs[baseId] = sch;
                    }
                    if (validateSchema)
                        this.validateSchema(schema, true);
                    return sch;
                }
                _checkUnique(id) {
                    if (this.schemas[id] || this.refs[id]) {
                        throw new Error(`schema with key or id "${id}" already exists`);
                    }
                }
                _compileSchemaEnv(sch) {
                    if (sch.meta)
                        this._compileMetaSchema(sch);
                    else
                        compile_1.compileSchema.call(this, sch);
                    /* istanbul ignore if */
                    if (!sch.validate)
                        throw new Error("ajv implementation error");
                    return sch.validate;
                }
                _compileMetaSchema(sch) {
                    const currentOpts = this.opts;
                    this.opts = this._metaOpts;
                    try {
                        compile_1.compileSchema.call(this, sch);
                    }
                    finally {
                        this.opts = currentOpts;
                    }
                }
            }
            exports.default = Ajv;
            Ajv.ValidationError = validation_error_1.default;
            Ajv.MissingRefError = ref_error_1.default;
            function checkOptions(checkOpts, options, msg, log = "error") {
                for (const key in checkOpts) {
                    const opt = key;
                    if (opt in options)
                        this.logger[log](`${msg}: option ${key}. ${checkOpts[opt]}`);
                }
            }
            function getSchEnv(keyRef) {
                keyRef = (0, resolve_1.normalizeId)(keyRef); // TODO tests fail without this line
                return this.schemas[keyRef] || this.refs[keyRef];
            }
            function addInitialSchemas() {
                const optsSchemas = this.opts.schemas;
                if (!optsSchemas)
                    return;
                if (Array.isArray(optsSchemas))
                    this.addSchema(optsSchemas);
                else
                    for (const key in optsSchemas)
                        this.addSchema(optsSchemas[key], key);
            }
            function addInitialFormats() {
                for (const name in this.opts.formats) {
                    const format = this.opts.formats[name];
                    if (format)
                        this.addFormat(name, format);
                }
            }
            function addInitialKeywords(defs) {
                if (Array.isArray(defs)) {
                    this.addVocabulary(defs);
                    return;
                }
                this.logger.warn("keywords option as map is deprecated, pass array");
                for (const keyword in defs) {
                    const def = defs[keyword];
                    if (!def.keyword)
                        def.keyword = keyword;
                    this.addKeyword(def);
                }
            }
            function getMetaSchemaOptions() {
                const metaOpts = { ...this.opts };
                for (const opt of META_IGNORE_OPTIONS)
                    delete metaOpts[opt];
                return metaOpts;
            }
            const noLogs = { log() { }, warn() { }, error() { } };
            function getLogger(logger) {
                if (logger === false)
                    return noLogs;
                if (logger === undefined)
                    return console;
                if (logger.log && logger.warn && logger.error)
                    return logger;
                throw new Error("logger must implement log, warn and error methods");
            }
            const KEYWORD_NAME = /^[a-z_$][a-z0-9_$:-]*$/i;
            function checkKeyword(keyword, def) {
                const { RULES } = this;
                (0, util_1.eachItem)(keyword, (kwd) => {
                    if (RULES.keywords[kwd])
                        throw new Error(`Keyword ${kwd} is already defined`);
                    if (!KEYWORD_NAME.test(kwd))
                        throw new Error(`Keyword ${kwd} has invalid name`);
                });
                if (!def)
                    return;
                if (def.$data && !("code" in def || "validate" in def)) {
                    throw new Error('$data keyword must have "code" or "validate" function');
                }
            }
            function addRule(keyword, definition, dataType) {
                var _a;
                const post = definition === null || definition === void 0 ? void 0 : definition.post;
                if (dataType && post)
                    throw new Error('keyword with "post" flag cannot have "type"');
                const { RULES } = this;
                let ruleGroup = post ? RULES.post : RULES.rules.find(({ type: t }) => t === dataType);
                if (!ruleGroup) {
                    ruleGroup = { type: dataType, rules: [] };
                    RULES.rules.push(ruleGroup);
                }
                RULES.keywords[keyword] = true;
                if (!definition)
                    return;
                const rule = {
                    keyword,
                    definition: {
                        ...definition,
                        type: (0, dataType_1.getJSONTypes)(definition.type),
                        schemaType: (0, dataType_1.getJSONTypes)(definition.schemaType),
                    },
                };
                if (definition.before)
                    addBeforeRule.call(this, ruleGroup, rule, definition.before);
                else
                    ruleGroup.rules.push(rule);
                RULES.all[keyword] = rule;
                (_a = definition.implements) === null || _a === void 0 ? void 0 : _a.forEach((kwd) => this.addKeyword(kwd));
            }
            function addBeforeRule(ruleGroup, rule, before) {
                const i = ruleGroup.rules.findIndex((_rule) => _rule.keyword === before);
                if (i >= 0) {
                    ruleGroup.rules.splice(i, 0, rule);
                }
                else {
                    ruleGroup.rules.push(rule);
                    this.logger.warn(`rule ${before} is not defined`);
                }
            }
            function keywordMetaschema(def) {
                let { metaSchema } = def;
                if (metaSchema === undefined)
                    return;
                if (def.$data && this.opts.$data)
                    metaSchema = schemaOrData(metaSchema);
                def.validateSchema = this.compile(metaSchema, true);
            }
            const $dataRef = {
                $ref: "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/data.json#",
            };
            function schemaOrData(schema) {
                return { anyOf: [schema, $dataRef] };
            }

        }, { "./compile": 41, "./compile/codegen": 38, "./compile/ref_error": 43, "./compile/resolve": 44, "./compile/rules": 45, "./compile/util": 46, "./compile/validate": 51, "./compile/validate/dataType": 49, "./refs/data.json": 55, "./runtime/validation_error": 59 }], 55: [function (require, module, exports) {
            module.exports = {
                "$id": "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/data.json#",
                "description": "Meta-schema for $data reference (JSON AnySchema extension proposal)",
                "type": "object",
                "required": ["$data"],
                "properties": {
                    "$data": {
                        "type": "string",
                        "anyOf": [{ "format": "relative-json-pointer" }, { "format": "json-pointer" }]
                    }
                },
                "additionalProperties": false
            }

        }, {}], 56: [function (require, module, exports) {
            module.exports = {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "$id": "http://json-schema.org/draft-07/schema#",
                "title": "Core schema meta-schema",
                "definitions": {
                    "schemaArray": {
                        "type": "array",
                        "minItems": 1,
                        "items": { "$ref": "#" }
                    },
                    "nonNegativeInteger": {
                        "type": "integer",
                        "minimum": 0
                    },
                    "nonNegativeIntegerDefault0": {
                        "allOf": [{ "$ref": "#/definitions/nonNegativeInteger" }, { "default": 0 }]
                    },
                    "simpleTypes": {
                        "enum": ["array", "boolean", "integer", "null", "number", "object", "string"]
                    },
                    "stringArray": {
                        "type": "array",
                        "items": { "type": "string" },
                        "uniqueItems": true,
                        "default": []
                    }
                },
                "type": ["object", "boolean"],
                "properties": {
                    "$id": {
                        "type": "string",
                        "format": "uri-reference"
                    },
                    "$schema": {
                        "type": "string",
                        "format": "uri"
                    },
                    "$ref": {
                        "type": "string",
                        "format": "uri-reference"
                    },
                    "$comment": {
                        "type": "string"
                    },
                    "title": {
                        "type": "string"
                    },
                    "description": {
                        "type": "string"
                    },
                    "default": true,
                    "readOnly": {
                        "type": "boolean",
                        "default": false
                    },
                    "examples": {
                        "type": "array",
                        "items": true
                    },
                    "multipleOf": {
                        "type": "number",
                        "exclusiveMinimum": 0
                    },
                    "maximum": {
                        "type": "number"
                    },
                    "exclusiveMaximum": {
                        "type": "number"
                    },
                    "minimum": {
                        "type": "number"
                    },
                    "exclusiveMinimum": {
                        "type": "number"
                    },
                    "maxLength": { "$ref": "#/definitions/nonNegativeInteger" },
                    "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
                    "pattern": {
                        "type": "string",
                        "format": "regex"
                    },
                    "additionalItems": { "$ref": "#" },
                    "items": {
                        "anyOf": [{ "$ref": "#" }, { "$ref": "#/definitions/schemaArray" }],
                        "default": true
                    },
                    "maxItems": { "$ref": "#/definitions/nonNegativeInteger" },
                    "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
                    "uniqueItems": {
                        "type": "boolean",
                        "default": false
                    },
                    "contains": { "$ref": "#" },
                    "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" },
                    "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
                    "required": { "$ref": "#/definitions/stringArray" },
                    "additionalProperties": { "$ref": "#" },
                    "definitions": {
                        "type": "object",
                        "additionalProperties": { "$ref": "#" },
                        "default": {}
                    },
                    "properties": {
                        "type": "object",
                        "additionalProperties": { "$ref": "#" },
                        "default": {}
                    },
                    "patternProperties": {
                        "type": "object",
                        "additionalProperties": { "$ref": "#" },
                        "propertyNames": { "format": "regex" },
                        "default": {}
                    },
                    "dependencies": {
                        "type": "object",
                        "additionalProperties": {
                            "anyOf": [{ "$ref": "#" }, { "$ref": "#/definitions/stringArray" }]
                        }
                    },
                    "propertyNames": { "$ref": "#" },
                    "const": true,
                    "enum": {
                        "type": "array",
                        "items": true,
                        "minItems": 1,
                        "uniqueItems": true
                    },
                    "type": {
                        "anyOf": [
                            { "$ref": "#/definitions/simpleTypes" },
                            {
                                "type": "array",
                                "items": { "$ref": "#/definitions/simpleTypes" },
                                "minItems": 1,
                                "uniqueItems": true
                            }
                        ]
                    },
                    "format": { "type": "string" },
                    "contentMediaType": { "type": "string" },
                    "contentEncoding": { "type": "string" },
                    "if": { "$ref": "#" },
                    "then": { "$ref": "#" },
                    "else": { "$ref": "#" },
                    "allOf": { "$ref": "#/definitions/schemaArray" },
                    "anyOf": { "$ref": "#/definitions/schemaArray" },
                    "oneOf": { "$ref": "#/definitions/schemaArray" },
                    "not": { "$ref": "#" }
                },
                "default": true
            }

        }, {}], 57: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            // https://github.com/ajv-validator/ajv/issues/889
            const equal = require("fast-deep-equal");
            equal.code = 'require("ajv/dist/runtime/equal").default';
            exports.default = equal;

        }, { "fast-deep-equal": 99 }], 58: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            // https://mathiasbynens.be/notes/javascript-encoding
            // https://github.com/bestiejs/punycode.js - punycode.ucs2.decode
            function ucs2length(str) {
                const len = str.length;
                let length = 0;
                let pos = 0;
                let value;
                while (pos < len) {
                    length++;
                    value = str.charCodeAt(pos++);
                    if (value >= 0xd800 && value <= 0xdbff && pos < len) {
                        // high surrogate, and there is a next character
                        value = str.charCodeAt(pos);
                        if ((value & 0xfc00) === 0xdc00)
                            pos++; // low surrogate
                    }
                }
                return length;
            }
            exports.default = ucs2length;
            ucs2length.code = 'require("ajv/dist/runtime/ucs2length").default';

        }, {}], 59: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            class ValidationError extends Error {
                constructor(errors) {
                    super("validation failed");
                    this.errors = errors;
                    this.ajv = this.validation = true;
                }
            }
            exports.default = ValidationError;

        }, {}], 60: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.validateAdditionalItems = void 0;
            const codegen_1 = require("../../compile/codegen");
            const util_1 = require("../../compile/util");
            const error = {
                message: ({ params: { len } }) => (0, codegen_1.str)`must NOT have more than ${len} items`,
                params: ({ params: { len } }) => (0, codegen_1._)`{limit: ${len}}`,
            };
            const def = {
                keyword: "additionalItems",
                type: "array",
                schemaType: ["boolean", "object"],
                before: "uniqueItems",
                error,
                code(cxt) {
                    const { parentSchema, it } = cxt;
                    const { items } = parentSchema;
                    if (!Array.isArray(items)) {
                        (0, util_1.checkStrictMode)(it, '"additionalItems" is ignored when "items" is not an array of schemas');
                        return;
                    }
                    validateAdditionalItems(cxt, items);
                },
            };
            function validateAdditionalItems(cxt, items) {
                const { gen, schema, data, keyword, it } = cxt;
                it.items = true;
                const len = gen.const("len", (0, codegen_1._)`${data}.length`);
                if (schema === false) {
                    cxt.setParams({ len: items.length });
                    cxt.pass((0, codegen_1._)`${len} <= ${items.length}`);
                }
                else if (typeof schema == "object" && !(0, util_1.alwaysValidSchema)(it, schema)) {
                    const valid = gen.var("valid", (0, codegen_1._)`${len} <= ${items.length}`); // TODO var
                    gen.if((0, codegen_1.not)(valid), () => validateItems(valid));
                    cxt.ok(valid);
                }
                function validateItems(valid) {
                    gen.forRange("i", items.length, len, (i) => {
                        cxt.subschema({ keyword, dataProp: i, dataPropType: util_1.Type.Num }, valid);
                        if (!it.allErrors)
                            gen.if((0, codegen_1.not)(valid), () => gen.break());
                    });
                }
            }
            exports.validateAdditionalItems = validateAdditionalItems;
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/util": 46 }], 61: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const code_1 = require("../code");
            const codegen_1 = require("../../compile/codegen");
            const names_1 = require("../../compile/names");
            const util_1 = require("../../compile/util");
            const error = {
                message: "must NOT have additional properties",
                params: ({ params }) => (0, codegen_1._)`{additionalProperty: ${params.additionalProperty}}`,
            };
            const def = {
                keyword: "additionalProperties",
                type: ["object"],
                schemaType: ["boolean", "object"],
                allowUndefined: true,
                trackErrors: true,
                error,
                code(cxt) {
                    const { gen, schema, parentSchema, data, errsCount, it } = cxt;
                    /* istanbul ignore if */
                    if (!errsCount)
                        throw new Error("ajv implementation error");
                    const { allErrors, opts } = it;
                    it.props = true;
                    if (opts.removeAdditional !== "all" && (0, util_1.alwaysValidSchema)(it, schema))
                        return;
                    const props = (0, code_1.allSchemaProperties)(parentSchema.properties);
                    const patProps = (0, code_1.allSchemaProperties)(parentSchema.patternProperties);
                    checkAdditionalProperties();
                    cxt.ok((0, codegen_1._)`${errsCount} === ${names_1.default.errors}`);
                    function checkAdditionalProperties() {
                        gen.forIn("key", data, (key) => {
                            if (!props.length && !patProps.length)
                                additionalPropertyCode(key);
                            else
                                gen.if(isAdditional(key), () => additionalPropertyCode(key));
                        });
                    }
                    function isAdditional(key) {
                        let definedProp;
                        if (props.length > 8) {
                            // TODO maybe an option instead of hard-coded 8?
                            const propsSchema = (0, util_1.schemaRefOrVal)(it, parentSchema.properties, "properties");
                            definedProp = (0, code_1.isOwnProperty)(gen, propsSchema, key);
                        }
                        else if (props.length) {
                            definedProp = (0, codegen_1.or)(...props.map((p) => (0, codegen_1._)`${key} === ${p}`));
                        }
                        else {
                            definedProp = codegen_1.nil;
                        }
                        if (patProps.length) {
                            definedProp = (0, codegen_1.or)(definedProp, ...patProps.map((p) => (0, codegen_1._)`${(0, code_1.usePattern)(cxt, p)}.test(${key})`));
                        }
                        return (0, codegen_1.not)(definedProp);
                    }
                    function deleteAdditional(key) {
                        gen.code((0, codegen_1._)`delete ${data}[${key}]`);
                    }
                    function additionalPropertyCode(key) {
                        if (opts.removeAdditional === "all" || (opts.removeAdditional && schema === false)) {
                            deleteAdditional(key);
                            return;
                        }
                        if (schema === false) {
                            cxt.setParams({ additionalProperty: key });
                            cxt.error();
                            if (!allErrors)
                                gen.break();
                            return;
                        }
                        if (typeof schema == "object" && !(0, util_1.alwaysValidSchema)(it, schema)) {
                            const valid = gen.name("valid");
                            if (opts.removeAdditional === "failing") {
                                applyAdditionalSchema(key, valid, false);
                                gen.if((0, codegen_1.not)(valid), () => {
                                    cxt.reset();
                                    deleteAdditional(key);
                                });
                            }
                            else {
                                applyAdditionalSchema(key, valid);
                                if (!allErrors)
                                    gen.if((0, codegen_1.not)(valid), () => gen.break());
                            }
                        }
                    }
                    function applyAdditionalSchema(key, valid, errors) {
                        const subschema = {
                            keyword: "additionalProperties",
                            dataProp: key,
                            dataPropType: util_1.Type.Str,
                        };
                        if (errors === false) {
                            Object.assign(subschema, {
                                compositeRule: true,
                                createErrors: false,
                                allErrors: false,
                            });
                        }
                        cxt.subschema(subschema, valid);
                    }
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/names": 42, "../../compile/util": 46, "../code": 77 }], 62: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const util_1 = require("../../compile/util");
            const def = {
                keyword: "allOf",
                schemaType: "array",
                code(cxt) {
                    const { gen, schema, it } = cxt;
                    /* istanbul ignore if */
                    if (!Array.isArray(schema))
                        throw new Error("ajv implementation error");
                    const valid = gen.name("valid");
                    schema.forEach((sch, i) => {
                        if ((0, util_1.alwaysValidSchema)(it, sch))
                            return;
                        const schCxt = cxt.subschema({ keyword: "allOf", schemaProp: i }, valid);
                        cxt.ok(valid);
                        cxt.mergeEvaluated(schCxt);
                    });
                },
            };
            exports.default = def;

        }, { "../../compile/util": 46 }], 63: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const code_1 = require("../code");
            const def = {
                keyword: "anyOf",
                schemaType: "array",
                trackErrors: true,
                code: code_1.validateUnion,
                error: { message: "must match a schema in anyOf" },
            };
            exports.default = def;

        }, { "../code": 77 }], 64: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("../../compile/codegen");
            const util_1 = require("../../compile/util");
            const error = {
                message: ({ params: { min, max } }) => max === undefined
                    ? (0, codegen_1.str)`must contain at least ${min} valid item(s)`
                    : (0, codegen_1.str)`must contain at least ${min} and no more than ${max} valid item(s)`,
                params: ({ params: { min, max } }) => max === undefined ? (0, codegen_1._)`{minContains: ${min}}` : (0, codegen_1._)`{minContains: ${min}, maxContains: ${max}}`,
            };
            const def = {
                keyword: "contains",
                type: "array",
                schemaType: ["object", "boolean"],
                before: "uniqueItems",
                trackErrors: true,
                error,
                code(cxt) {
                    const { gen, schema, parentSchema, data, it } = cxt;
                    let min;
                    let max;
                    const { minContains, maxContains } = parentSchema;
                    if (it.opts.next) {
                        min = minContains === undefined ? 1 : minContains;
                        max = maxContains;
                    }
                    else {
                        min = 1;
                    }
                    const len = gen.const("len", (0, codegen_1._)`${data}.length`);
                    cxt.setParams({ min, max });
                    if (max === undefined && min === 0) {
                        (0, util_1.checkStrictMode)(it, `"minContains" == 0 without "maxContains": "contains" keyword ignored`);
                        return;
                    }
                    if (max !== undefined && min > max) {
                        (0, util_1.checkStrictMode)(it, `"minContains" > "maxContains" is always invalid`);
                        cxt.fail();
                        return;
                    }
                    if ((0, util_1.alwaysValidSchema)(it, schema)) {
                        let cond = (0, codegen_1._)`${len} >= ${min}`;
                        if (max !== undefined)
                            cond = (0, codegen_1._)`${cond} && ${len} <= ${max}`;
                        cxt.pass(cond);
                        return;
                    }
                    it.items = true;
                    const valid = gen.name("valid");
                    if (max === undefined && min === 1) {
                        validateItems(valid, () => gen.if(valid, () => gen.break()));
                    }
                    else if (min === 0) {
                        gen.let(valid, true);
                        if (max !== undefined)
                            gen.if((0, codegen_1._)`${data}.length > 0`, validateItemsWithCount);
                    }
                    else {
                        gen.let(valid, false);
                        validateItemsWithCount();
                    }
                    cxt.result(valid, () => cxt.reset());
                    function validateItemsWithCount() {
                        const schValid = gen.name("_valid");
                        const count = gen.let("count", 0);
                        validateItems(schValid, () => gen.if(schValid, () => checkLimits(count)));
                    }
                    function validateItems(_valid, block) {
                        gen.forRange("i", 0, len, (i) => {
                            cxt.subschema({
                                keyword: "contains",
                                dataProp: i,
                                dataPropType: util_1.Type.Num,
                                compositeRule: true,
                            }, _valid);
                            block();
                        });
                    }
                    function checkLimits(count) {
                        gen.code((0, codegen_1._)`${count}++`);
                        if (max === undefined) {
                            gen.if((0, codegen_1._)`${count} >= ${min}`, () => gen.assign(valid, true).break());
                        }
                        else {
                            gen.if((0, codegen_1._)`${count} > ${max}`, () => gen.assign(valid, false).break());
                            if (min === 1)
                                gen.assign(valid, true);
                            else
                                gen.if((0, codegen_1._)`${count} >= ${min}`, () => gen.assign(valid, true));
                        }
                    }
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/util": 46 }], 65: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.validateSchemaDeps = exports.validatePropertyDeps = exports.error = void 0;
            const codegen_1 = require("../../compile/codegen");
            const util_1 = require("../../compile/util");
            const code_1 = require("../code");
            exports.error = {
                message: ({ params: { property, depsCount, deps } }) => {
                    const property_ies = depsCount === 1 ? "property" : "properties";
                    return (0, codegen_1.str)`must have ${property_ies} ${deps} when property ${property} is present`;
                },
                params: ({ params: { property, depsCount, deps, missingProperty } }) => (0, codegen_1._)`{property: ${property},
    missingProperty: ${missingProperty},
    depsCount: ${depsCount},
    deps: ${deps}}`, // TODO change to reference
            };
            const def = {
                keyword: "dependencies",
                type: "object",
                schemaType: "object",
                error: exports.error,
                code(cxt) {
                    const [propDeps, schDeps] = splitDependencies(cxt);
                    validatePropertyDeps(cxt, propDeps);
                    validateSchemaDeps(cxt, schDeps);
                },
            };
            function splitDependencies({ schema }) {
                const propertyDeps = {};
                const schemaDeps = {};
                for (const key in schema) {
                    if (key === "__proto__")
                        continue;
                    const deps = Array.isArray(schema[key]) ? propertyDeps : schemaDeps;
                    deps[key] = schema[key];
                }
                return [propertyDeps, schemaDeps];
            }
            function validatePropertyDeps(cxt, propertyDeps = cxt.schema) {
                const { gen, data, it } = cxt;
                if (Object.keys(propertyDeps).length === 0)
                    return;
                const missing = gen.let("missing");
                for (const prop in propertyDeps) {
                    const deps = propertyDeps[prop];
                    if (deps.length === 0)
                        continue;
                    const hasProperty = (0, code_1.propertyInData)(gen, data, prop, it.opts.ownProperties);
                    cxt.setParams({
                        property: prop,
                        depsCount: deps.length,
                        deps: deps.join(", "),
                    });
                    if (it.allErrors) {
                        gen.if(hasProperty, () => {
                            for (const depProp of deps) {
                                (0, code_1.checkReportMissingProp)(cxt, depProp);
                            }
                        });
                    }
                    else {
                        gen.if((0, codegen_1._)`${hasProperty} && (${(0, code_1.checkMissingProp)(cxt, deps, missing)})`);
                        (0, code_1.reportMissingProp)(cxt, missing);
                        gen.else();
                    }
                }
            }
            exports.validatePropertyDeps = validatePropertyDeps;
            function validateSchemaDeps(cxt, schemaDeps = cxt.schema) {
                const { gen, data, keyword, it } = cxt;
                const valid = gen.name("valid");
                for (const prop in schemaDeps) {
                    if ((0, util_1.alwaysValidSchema)(it, schemaDeps[prop]))
                        continue;
                    gen.if((0, code_1.propertyInData)(gen, data, prop, it.opts.ownProperties), () => {
                        const schCxt = cxt.subschema({ keyword, schemaProp: prop }, valid);
                        cxt.mergeValidEvaluated(schCxt, valid);
                    }, () => gen.var(valid, true) // TODO var
                    );
                    cxt.ok(valid);
                }
            }
            exports.validateSchemaDeps = validateSchemaDeps;
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/util": 46, "../code": 77 }], 66: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("../../compile/codegen");
            const util_1 = require("../../compile/util");
            const error = {
                message: ({ params }) => (0, codegen_1.str)`must match "${params.ifClause}" schema`,
                params: ({ params }) => (0, codegen_1._)`{failingKeyword: ${params.ifClause}}`,
            };
            const def = {
                keyword: "if",
                schemaType: ["object", "boolean"],
                trackErrors: true,
                error,
                code(cxt) {
                    const { gen, parentSchema, it } = cxt;
                    if (parentSchema.then === undefined && parentSchema.else === undefined) {
                        (0, util_1.checkStrictMode)(it, '"if" without "then" and "else" is ignored');
                    }
                    const hasThen = hasSchema(it, "then");
                    const hasElse = hasSchema(it, "else");
                    if (!hasThen && !hasElse)
                        return;
                    const valid = gen.let("valid", true);
                    const schValid = gen.name("_valid");
                    validateIf();
                    cxt.reset();
                    if (hasThen && hasElse) {
                        const ifClause = gen.let("ifClause");
                        cxt.setParams({ ifClause });
                        gen.if(schValid, validateClause("then", ifClause), validateClause("else", ifClause));
                    }
                    else if (hasThen) {
                        gen.if(schValid, validateClause("then"));
                    }
                    else {
                        gen.if((0, codegen_1.not)(schValid), validateClause("else"));
                    }
                    cxt.pass(valid, () => cxt.error(true));
                    function validateIf() {
                        const schCxt = cxt.subschema({
                            keyword: "if",
                            compositeRule: true,
                            createErrors: false,
                            allErrors: false,
                        }, schValid);
                        cxt.mergeEvaluated(schCxt);
                    }
                    function validateClause(keyword, ifClause) {
                        return () => {
                            const schCxt = cxt.subschema({ keyword }, schValid);
                            gen.assign(valid, schValid);
                            cxt.mergeValidEvaluated(schCxt, valid);
                            if (ifClause)
                                gen.assign(ifClause, (0, codegen_1._)`${keyword}`);
                            else
                                cxt.setParams({ ifClause: keyword });
                        };
                    }
                },
            };
            function hasSchema(it, keyword) {
                const schema = it.schema[keyword];
                return schema !== undefined && !(0, util_1.alwaysValidSchema)(it, schema);
            }
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/util": 46 }], 67: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const additionalItems_1 = require("./additionalItems");
            const prefixItems_1 = require("./prefixItems");
            const items_1 = require("./items");
            const items2020_1 = require("./items2020");
            const contains_1 = require("./contains");
            const dependencies_1 = require("./dependencies");
            const propertyNames_1 = require("./propertyNames");
            const additionalProperties_1 = require("./additionalProperties");
            const properties_1 = require("./properties");
            const patternProperties_1 = require("./patternProperties");
            const not_1 = require("./not");
            const anyOf_1 = require("./anyOf");
            const oneOf_1 = require("./oneOf");
            const allOf_1 = require("./allOf");
            const if_1 = require("./if");
            const thenElse_1 = require("./thenElse");
            function getApplicator(draft2020 = false) {
                const applicator = [
                    // any
                    not_1.default,
                    anyOf_1.default,
                    oneOf_1.default,
                    allOf_1.default,
                    if_1.default,
                    thenElse_1.default,
                    // object
                    propertyNames_1.default,
                    additionalProperties_1.default,
                    dependencies_1.default,
                    properties_1.default,
                    patternProperties_1.default,
                ];
                // array
                if (draft2020)
                    applicator.push(prefixItems_1.default, items2020_1.default);
                else
                    applicator.push(additionalItems_1.default, items_1.default);
                applicator.push(contains_1.default);
                return applicator;
            }
            exports.default = getApplicator;

        }, { "./additionalItems": 60, "./additionalProperties": 61, "./allOf": 62, "./anyOf": 63, "./contains": 64, "./dependencies": 65, "./if": 66, "./items": 68, "./items2020": 69, "./not": 70, "./oneOf": 71, "./patternProperties": 72, "./prefixItems": 73, "./properties": 74, "./propertyNames": 75, "./thenElse": 76 }], 68: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.validateTuple = void 0;
            const codegen_1 = require("../../compile/codegen");
            const util_1 = require("../../compile/util");
            const code_1 = require("../code");
            const def = {
                keyword: "items",
                type: "array",
                schemaType: ["object", "array", "boolean"],
                before: "uniqueItems",
                code(cxt) {
                    const { schema, it } = cxt;
                    if (Array.isArray(schema))
                        return validateTuple(cxt, "additionalItems", schema);
                    it.items = true;
                    if ((0, util_1.alwaysValidSchema)(it, schema))
                        return;
                    cxt.ok((0, code_1.validateArray)(cxt));
                },
            };
            function validateTuple(cxt, extraItems, schArr = cxt.schema) {
                const { gen, parentSchema, data, keyword, it } = cxt;
                checkStrictTuple(parentSchema);
                if (it.opts.unevaluated && schArr.length && it.items !== true) {
                    it.items = util_1.mergeEvaluated.items(gen, schArr.length, it.items);
                }
                const valid = gen.name("valid");
                const len = gen.const("len", (0, codegen_1._)`${data}.length`);
                schArr.forEach((sch, i) => {
                    if ((0, util_1.alwaysValidSchema)(it, sch))
                        return;
                    gen.if((0, codegen_1._)`${len} > ${i}`, () => cxt.subschema({
                        keyword,
                        schemaProp: i,
                        dataProp: i,
                    }, valid));
                    cxt.ok(valid);
                });
                function checkStrictTuple(sch) {
                    const { opts, errSchemaPath } = it;
                    const l = schArr.length;
                    const fullTuple = l === sch.minItems && (l === sch.maxItems || sch[extraItems] === false);
                    if (opts.strictTuples && !fullTuple) {
                        const msg = `"${keyword}" is ${l}-tuple, but minItems or maxItems/${extraItems} are not specified or different at path "${errSchemaPath}"`;
                        (0, util_1.checkStrictMode)(it, msg, opts.strictTuples);
                    }
                }
            }
            exports.validateTuple = validateTuple;
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/util": 46, "../code": 77 }], 69: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("../../compile/codegen");
            const util_1 = require("../../compile/util");
            const code_1 = require("../code");
            const additionalItems_1 = require("./additionalItems");
            const error = {
                message: ({ params: { len } }) => (0, codegen_1.str)`must NOT have more than ${len} items`,
                params: ({ params: { len } }) => (0, codegen_1._)`{limit: ${len}}`,
            };
            const def = {
                keyword: "items",
                type: "array",
                schemaType: ["object", "boolean"],
                before: "uniqueItems",
                error,
                code(cxt) {
                    const { schema, parentSchema, it } = cxt;
                    const { prefixItems } = parentSchema;
                    it.items = true;
                    if ((0, util_1.alwaysValidSchema)(it, schema))
                        return;
                    if (prefixItems)
                        (0, additionalItems_1.validateAdditionalItems)(cxt, prefixItems);
                    else
                        cxt.ok((0, code_1.validateArray)(cxt));
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/util": 46, "../code": 77, "./additionalItems": 60 }], 70: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const util_1 = require("../../compile/util");
            const def = {
                keyword: "not",
                schemaType: ["object", "boolean"],
                trackErrors: true,
                code(cxt) {
                    const { gen, schema, it } = cxt;
                    if ((0, util_1.alwaysValidSchema)(it, schema)) {
                        cxt.fail();
                        return;
                    }
                    const valid = gen.name("valid");
                    cxt.subschema({
                        keyword: "not",
                        compositeRule: true,
                        createErrors: false,
                        allErrors: false,
                    }, valid);
                    cxt.failResult(valid, () => cxt.reset(), () => cxt.error());
                },
                error: { message: "must NOT be valid" },
            };
            exports.default = def;

        }, { "../../compile/util": 46 }], 71: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("../../compile/codegen");
            const util_1 = require("../../compile/util");
            const error = {
                message: "must match exactly one schema in oneOf",
                params: ({ params }) => (0, codegen_1._)`{passingSchemas: ${params.passing}}`,
            };
            const def = {
                keyword: "oneOf",
                schemaType: "array",
                trackErrors: true,
                error,
                code(cxt) {
                    const { gen, schema, parentSchema, it } = cxt;
                    /* istanbul ignore if */
                    if (!Array.isArray(schema))
                        throw new Error("ajv implementation error");
                    if (it.opts.discriminator && parentSchema.discriminator)
                        return;
                    const schArr = schema;
                    const valid = gen.let("valid", false);
                    const passing = gen.let("passing", null);
                    const schValid = gen.name("_valid");
                    cxt.setParams({ passing });
                    // TODO possibly fail straight away (with warning or exception) if there are two empty always valid schemas
                    gen.block(validateOneOf);
                    cxt.result(valid, () => cxt.reset(), () => cxt.error(true));
                    function validateOneOf() {
                        schArr.forEach((sch, i) => {
                            let schCxt;
                            if ((0, util_1.alwaysValidSchema)(it, sch)) {
                                gen.var(schValid, true);
                            }
                            else {
                                schCxt = cxt.subschema({
                                    keyword: "oneOf",
                                    schemaProp: i,
                                    compositeRule: true,
                                }, schValid);
                            }
                            if (i > 0) {
                                gen
                                    .if((0, codegen_1._)`${schValid} && ${valid}`)
                                    .assign(valid, false)
                                    .assign(passing, (0, codegen_1._)`[${passing}, ${i}]`)
                                    .else();
                            }
                            gen.if(schValid, () => {
                                gen.assign(valid, true);
                                gen.assign(passing, i);
                                if (schCxt)
                                    cxt.mergeEvaluated(schCxt, codegen_1.Name);
                            });
                        });
                    }
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/util": 46 }], 72: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const code_1 = require("../code");
            const codegen_1 = require("../../compile/codegen");
            const util_1 = require("../../compile/util");
            const util_2 = require("../../compile/util");
            const def = {
                keyword: "patternProperties",
                type: "object",
                schemaType: "object",
                code(cxt) {
                    const { gen, schema, data, parentSchema, it } = cxt;
                    const { opts } = it;
                    const patterns = (0, code_1.allSchemaProperties)(schema);
                    const alwaysValidPatterns = patterns.filter((p) => (0, util_1.alwaysValidSchema)(it, schema[p]));
                    if (patterns.length === 0 ||
                        (alwaysValidPatterns.length === patterns.length &&
                            (!it.opts.unevaluated || it.props === true))) {
                        return;
                    }
                    const checkProperties = opts.strictSchema && !opts.allowMatchingProperties && parentSchema.properties;
                    const valid = gen.name("valid");
                    if (it.props !== true && !(it.props instanceof codegen_1.Name)) {
                        it.props = (0, util_2.evaluatedPropsToName)(gen, it.props);
                    }
                    const { props } = it;
                    validatePatternProperties();
                    function validatePatternProperties() {
                        for (const pat of patterns) {
                            if (checkProperties)
                                checkMatchingProperties(pat);
                            if (it.allErrors) {
                                validateProperties(pat);
                            }
                            else {
                                gen.var(valid, true); // TODO var
                                validateProperties(pat);
                                gen.if(valid);
                            }
                        }
                    }
                    function checkMatchingProperties(pat) {
                        for (const prop in checkProperties) {
                            if (new RegExp(pat).test(prop)) {
                                (0, util_1.checkStrictMode)(it, `property ${prop} matches pattern ${pat} (use allowMatchingProperties)`);
                            }
                        }
                    }
                    function validateProperties(pat) {
                        gen.forIn("key", data, (key) => {
                            gen.if((0, codegen_1._)`${(0, code_1.usePattern)(cxt, pat)}.test(${key})`, () => {
                                const alwaysValid = alwaysValidPatterns.includes(pat);
                                if (!alwaysValid) {
                                    cxt.subschema({
                                        keyword: "patternProperties",
                                        schemaProp: pat,
                                        dataProp: key,
                                        dataPropType: util_2.Type.Str,
                                    }, valid);
                                }
                                if (it.opts.unevaluated && props !== true) {
                                    gen.assign((0, codegen_1._)`${props}[${key}]`, true);
                                }
                                else if (!alwaysValid && !it.allErrors) {
                                    // can short-circuit if `unevaluatedProperties` is not supported (opts.next === false)
                                    // or if all properties were evaluated (props === true)
                                    gen.if((0, codegen_1.not)(valid), () => gen.break());
                                }
                            });
                        });
                    }
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/util": 46, "../code": 77 }], 73: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const items_1 = require("./items");
            const def = {
                keyword: "prefixItems",
                type: "array",
                schemaType: ["array"],
                before: "uniqueItems",
                code: (cxt) => (0, items_1.validateTuple)(cxt, "items"),
            };
            exports.default = def;

        }, { "./items": 68 }], 74: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const validate_1 = require("../../compile/validate");
            const code_1 = require("../code");
            const util_1 = require("../../compile/util");
            const additionalProperties_1 = require("./additionalProperties");
            const def = {
                keyword: "properties",
                type: "object",
                schemaType: "object",
                code(cxt) {
                    const { gen, schema, parentSchema, data, it } = cxt;
                    if (it.opts.removeAdditional === "all" && parentSchema.additionalProperties === undefined) {
                        additionalProperties_1.default.code(new validate_1.KeywordCxt(it, additionalProperties_1.default, "additionalProperties"));
                    }
                    const allProps = (0, code_1.allSchemaProperties)(schema);
                    for (const prop of allProps) {
                        it.definedProperties.add(prop);
                    }
                    if (it.opts.unevaluated && allProps.length && it.props !== true) {
                        it.props = util_1.mergeEvaluated.props(gen, (0, util_1.toHash)(allProps), it.props);
                    }
                    const properties = allProps.filter((p) => !(0, util_1.alwaysValidSchema)(it, schema[p]));
                    if (properties.length === 0)
                        return;
                    const valid = gen.name("valid");
                    for (const prop of properties) {
                        if (hasDefault(prop)) {
                            applyPropertySchema(prop);
                        }
                        else {
                            gen.if((0, code_1.propertyInData)(gen, data, prop, it.opts.ownProperties));
                            applyPropertySchema(prop);
                            if (!it.allErrors)
                                gen.else().var(valid, true);
                            gen.endIf();
                        }
                        cxt.it.definedProperties.add(prop);
                        cxt.ok(valid);
                    }
                    function hasDefault(prop) {
                        return it.opts.useDefaults && !it.compositeRule && schema[prop].default !== undefined;
                    }
                    function applyPropertySchema(prop) {
                        cxt.subschema({
                            keyword: "properties",
                            schemaProp: prop,
                            dataProp: prop,
                        }, valid);
                    }
                },
            };
            exports.default = def;

        }, { "../../compile/util": 46, "../../compile/validate": 51, "../code": 77, "./additionalProperties": 61 }], 75: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("../../compile/codegen");
            const util_1 = require("../../compile/util");
            const error = {
                message: "property name must be valid",
                params: ({ params }) => (0, codegen_1._)`{propertyName: ${params.propertyName}}`,
            };
            const def = {
                keyword: "propertyNames",
                type: "object",
                schemaType: ["object", "boolean"],
                error,
                code(cxt) {
                    const { gen, schema, data, it } = cxt;
                    if ((0, util_1.alwaysValidSchema)(it, schema))
                        return;
                    const valid = gen.name("valid");
                    gen.forIn("key", data, (key) => {
                        cxt.setParams({ propertyName: key });
                        cxt.subschema({
                            keyword: "propertyNames",
                            data: key,
                            dataTypes: ["string"],
                            propertyName: key,
                            compositeRule: true,
                        }, valid);
                        gen.if((0, codegen_1.not)(valid), () => {
                            cxt.error(true);
                            if (!it.allErrors)
                                gen.break();
                        });
                    });
                    cxt.ok(valid);
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/util": 46 }], 76: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const util_1 = require("../../compile/util");
            const def = {
                keyword: ["then", "else"],
                schemaType: ["object", "boolean"],
                code({ keyword, parentSchema, it }) {
                    if (parentSchema.if === undefined)
                        (0, util_1.checkStrictMode)(it, `"${keyword}" without "if" is ignored`);
                },
            };
            exports.default = def;

        }, { "../../compile/util": 46 }], 77: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.validateUnion = exports.validateArray = exports.usePattern = exports.callValidateCode = exports.schemaProperties = exports.allSchemaProperties = exports.noPropertyInData = exports.propertyInData = exports.isOwnProperty = exports.hasPropFunc = exports.reportMissingProp = exports.checkMissingProp = exports.checkReportMissingProp = void 0;
            const codegen_1 = require("../compile/codegen");
            const util_1 = require("../compile/util");
            const names_1 = require("../compile/names");
            const util_2 = require("../compile/util");
            function checkReportMissingProp(cxt, prop) {
                const { gen, data, it } = cxt;
                gen.if(noPropertyInData(gen, data, prop, it.opts.ownProperties), () => {
                    cxt.setParams({ missingProperty: (0, codegen_1._)`${prop}` }, true);
                    cxt.error();
                });
            }
            exports.checkReportMissingProp = checkReportMissingProp;
            function checkMissingProp({ gen, data, it: { opts } }, properties, missing) {
                return (0, codegen_1.or)(...properties.map((prop) => (0, codegen_1.and)(noPropertyInData(gen, data, prop, opts.ownProperties), (0, codegen_1._)`${missing} = ${prop}`)));
            }
            exports.checkMissingProp = checkMissingProp;
            function reportMissingProp(cxt, missing) {
                cxt.setParams({ missingProperty: missing }, true);
                cxt.error();
            }
            exports.reportMissingProp = reportMissingProp;
            function hasPropFunc(gen) {
                return gen.scopeValue("func", {
                    // eslint-disable-next-line @typescript-eslint/unbound-method
                    ref: Object.prototype.hasOwnProperty,
                    code: (0, codegen_1._)`Object.prototype.hasOwnProperty`,
                });
            }
            exports.hasPropFunc = hasPropFunc;
            function isOwnProperty(gen, data, property) {
                return (0, codegen_1._)`${hasPropFunc(gen)}.call(${data}, ${property})`;
            }
            exports.isOwnProperty = isOwnProperty;
            function propertyInData(gen, data, property, ownProperties) {
                const cond = (0, codegen_1._)`${data}${(0, codegen_1.getProperty)(property)} !== undefined`;
                return ownProperties ? (0, codegen_1._)`${cond} && ${isOwnProperty(gen, data, property)}` : cond;
            }
            exports.propertyInData = propertyInData;
            function noPropertyInData(gen, data, property, ownProperties) {
                const cond = (0, codegen_1._)`${data}${(0, codegen_1.getProperty)(property)} === undefined`;
                return ownProperties ? (0, codegen_1.or)(cond, (0, codegen_1.not)(isOwnProperty(gen, data, property))) : cond;
            }
            exports.noPropertyInData = noPropertyInData;
            function allSchemaProperties(schemaMap) {
                return schemaMap ? Object.keys(schemaMap).filter((p) => p !== "__proto__") : [];
            }
            exports.allSchemaProperties = allSchemaProperties;
            function schemaProperties(it, schemaMap) {
                return allSchemaProperties(schemaMap).filter((p) => !(0, util_1.alwaysValidSchema)(it, schemaMap[p]));
            }
            exports.schemaProperties = schemaProperties;
            function callValidateCode({ schemaCode, data, it: { gen, topSchemaRef, schemaPath, errorPath }, it }, func, context, passSchema) {
                const dataAndSchema = passSchema ? (0, codegen_1._)`${schemaCode}, ${data}, ${topSchemaRef}${schemaPath}` : data;
                const valCxt = [
                    [names_1.default.instancePath, (0, codegen_1.strConcat)(names_1.default.instancePath, errorPath)],
                    [names_1.default.parentData, it.parentData],
                    [names_1.default.parentDataProperty, it.parentDataProperty],
                    [names_1.default.rootData, names_1.default.rootData],
                ];
                if (it.opts.dynamicRef)
                    valCxt.push([names_1.default.dynamicAnchors, names_1.default.dynamicAnchors]);
                const args = (0, codegen_1._)`${dataAndSchema}, ${gen.object(...valCxt)}`;
                return context !== codegen_1.nil ? (0, codegen_1._)`${func}.call(${context}, ${args})` : (0, codegen_1._)`${func}(${args})`;
            }
            exports.callValidateCode = callValidateCode;
            const newRegExp = (0, codegen_1._)`new RegExp`;
            function usePattern({ gen, it: { opts } }, pattern) {
                const u = opts.unicodeRegExp ? "u" : "";
                const { regExp } = opts.code;
                return gen.scopeValue("pattern", {
                    key: pattern,
                    ref: regExp(pattern, u),
                    code: (0, codegen_1._)`${regExp.code === "new RegExp" ? newRegExp : (0, util_2.useFunc)(gen, regExp)}(${pattern}, ${u})`,
                });
            }
            exports.usePattern = usePattern;
            function validateArray(cxt) {
                const { gen, data, keyword, it } = cxt;
                const valid = gen.name("valid");
                if (it.allErrors) {
                    const validArr = gen.let("valid", true);
                    validateItems(() => gen.assign(validArr, false));
                    return validArr;
                }
                gen.var(valid, true);
                validateItems(() => gen.break());
                return valid;
                function validateItems(notValid) {
                    const len = gen.const("len", (0, codegen_1._)`${data}.length`);
                    gen.forRange("i", 0, len, (i) => {
                        cxt.subschema({
                            keyword,
                            dataProp: i,
                            dataPropType: util_1.Type.Num,
                        }, valid);
                        gen.if((0, codegen_1.not)(valid), notValid);
                    });
                }
            }
            exports.validateArray = validateArray;
            function validateUnion(cxt) {
                const { gen, schema, keyword, it } = cxt;
                /* istanbul ignore if */
                if (!Array.isArray(schema))
                    throw new Error("ajv implementation error");
                const alwaysValid = schema.some((sch) => (0, util_1.alwaysValidSchema)(it, sch));
                if (alwaysValid && !it.opts.unevaluated)
                    return;
                const valid = gen.let("valid", false);
                const schValid = gen.name("_valid");
                gen.block(() => schema.forEach((_sch, i) => {
                    const schCxt = cxt.subschema({
                        keyword,
                        schemaProp: i,
                        compositeRule: true,
                    }, schValid);
                    gen.assign(valid, (0, codegen_1._)`${valid} || ${schValid}`);
                    const merged = cxt.mergeValidEvaluated(schCxt, schValid);
                    // can short-circuit if `unevaluatedProperties/Items` not supported (opts.unevaluated !== true)
                    // or if all properties and items were evaluated (it.props === true && it.items === true)
                    if (!merged)
                        gen.if((0, codegen_1.not)(valid));
                }));
                cxt.result(valid, () => cxt.reset(), () => cxt.error(true));
            }
            exports.validateUnion = validateUnion;

        }, { "../compile/codegen": 38, "../compile/names": 42, "../compile/util": 46 }], 78: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const def = {
                keyword: "id",
                code() {
                    throw new Error('NOT SUPPORTED: keyword "id", use "$id" for schema ID');
                },
            };
            exports.default = def;

        }, {}], 79: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const id_1 = require("./id");
            const ref_1 = require("./ref");
            const core = [
                "$schema",
                "$id",
                "$defs",
                "$vocabulary",
                { keyword: "$comment" },
                "definitions",
                id_1.default,
                ref_1.default,
            ];
            exports.default = core;

        }, { "./id": 78, "./ref": 80 }], 80: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.callRef = exports.getValidate = void 0;
            const ref_error_1 = require("../../compile/ref_error");
            const code_1 = require("../code");
            const codegen_1 = require("../../compile/codegen");
            const names_1 = require("../../compile/names");
            const compile_1 = require("../../compile");
            const util_1 = require("../../compile/util");
            const def = {
                keyword: "$ref",
                schemaType: "string",
                code(cxt) {
                    const { gen, schema: $ref, it } = cxt;
                    const { baseId, schemaEnv: env, validateName, opts, self } = it;
                    const { root } = env;
                    if (($ref === "#" || $ref === "#/") && baseId === root.baseId)
                        return callRootRef();
                    const schOrEnv = compile_1.resolveRef.call(self, root, baseId, $ref);
                    if (schOrEnv === undefined)
                        throw new ref_error_1.default(baseId, $ref);
                    if (schOrEnv instanceof compile_1.SchemaEnv)
                        return callValidate(schOrEnv);
                    return inlineRefSchema(schOrEnv);
                    function callRootRef() {
                        if (env === root)
                            return callRef(cxt, validateName, env, env.$async);
                        const rootName = gen.scopeValue("root", { ref: root });
                        return callRef(cxt, (0, codegen_1._)`${rootName}.validate`, root, root.$async);
                    }
                    function callValidate(sch) {
                        const v = getValidate(cxt, sch);
                        callRef(cxt, v, sch, sch.$async);
                    }
                    function inlineRefSchema(sch) {
                        const schName = gen.scopeValue("schema", opts.code.source === true ? { ref: sch, code: (0, codegen_1.stringify)(sch) } : { ref: sch });
                        const valid = gen.name("valid");
                        const schCxt = cxt.subschema({
                            schema: sch,
                            dataTypes: [],
                            schemaPath: codegen_1.nil,
                            topSchemaRef: schName,
                            errSchemaPath: $ref,
                        }, valid);
                        cxt.mergeEvaluated(schCxt);
                        cxt.ok(valid);
                    }
                },
            };
            function getValidate(cxt, sch) {
                const { gen } = cxt;
                return sch.validate
                    ? gen.scopeValue("validate", { ref: sch.validate })
                    : (0, codegen_1._)`${gen.scopeValue("wrapper", { ref: sch })}.validate`;
            }
            exports.getValidate = getValidate;
            function callRef(cxt, v, sch, $async) {
                const { gen, it } = cxt;
                const { allErrors, schemaEnv: env, opts } = it;
                const passCxt = opts.passContext ? names_1.default.this : codegen_1.nil;
                if ($async)
                    callAsyncRef();
                else
                    callSyncRef();
                function callAsyncRef() {
                    if (!env.$async)
                        throw new Error("async schema referenced by sync schema");
                    const valid = gen.let("valid");
                    gen.try(() => {
                        gen.code((0, codegen_1._)`await ${(0, code_1.callValidateCode)(cxt, v, passCxt)}`);
                        addEvaluatedFrom(v); // TODO will not work with async, it has to be returned with the result
                        if (!allErrors)
                            gen.assign(valid, true);
                    }, (e) => {
                        gen.if((0, codegen_1._)`!(${e} instanceof ${it.ValidationError})`, () => gen.throw(e));
                        addErrorsFrom(e);
                        if (!allErrors)
                            gen.assign(valid, false);
                    });
                    cxt.ok(valid);
                }
                function callSyncRef() {
                    cxt.result((0, code_1.callValidateCode)(cxt, v, passCxt), () => addEvaluatedFrom(v), () => addErrorsFrom(v));
                }
                function addErrorsFrom(source) {
                    const errs = (0, codegen_1._)`${source}.errors`;
                    gen.assign(names_1.default.vErrors, (0, codegen_1._)`${names_1.default.vErrors} === null ? ${errs} : ${names_1.default.vErrors}.concat(${errs})`); // TODO tagged
                    gen.assign(names_1.default.errors, (0, codegen_1._)`${names_1.default.vErrors}.length`);
                }
                function addEvaluatedFrom(source) {
                    var _a;
                    if (!it.opts.unevaluated)
                        return;
                    const schEvaluated = (_a = sch === null || sch === void 0 ? void 0 : sch.validate) === null || _a === void 0 ? void 0 : _a.evaluated;
                    // TODO refactor
                    if (it.props !== true) {
                        if (schEvaluated && !schEvaluated.dynamicProps) {
                            if (schEvaluated.props !== undefined) {
                                it.props = util_1.mergeEvaluated.props(gen, schEvaluated.props, it.props);
                            }
                        }
                        else {
                            const props = gen.var("props", (0, codegen_1._)`${source}.evaluated.props`);
                            it.props = util_1.mergeEvaluated.props(gen, props, it.props, codegen_1.Name);
                        }
                    }
                    if (it.items !== true) {
                        if (schEvaluated && !schEvaluated.dynamicItems) {
                            if (schEvaluated.items !== undefined) {
                                it.items = util_1.mergeEvaluated.items(gen, schEvaluated.items, it.items);
                            }
                        }
                        else {
                            const items = gen.var("items", (0, codegen_1._)`${source}.evaluated.items`);
                            it.items = util_1.mergeEvaluated.items(gen, items, it.items, codegen_1.Name);
                        }
                    }
                }
            }
            exports.callRef = callRef;
            exports.default = def;

        }, { "../../compile": 41, "../../compile/codegen": 38, "../../compile/names": 42, "../../compile/ref_error": 43, "../../compile/util": 46, "../code": 77 }], 81: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("../../compile/codegen");
            const types_1 = require("../discriminator/types");
            const error = {
                message: ({ params: { discrError, tagName } }) => discrError === types_1.DiscrError.Tag
                    ? `tag "${tagName}" must be string`
                    : `value of tag "${tagName}" must be in oneOf`,
                params: ({ params: { discrError, tag, tagName } }) => (0, codegen_1._)`{error: ${discrError}, tag: ${tagName}, tagValue: ${tag}}`,
            };
            const def = {
                keyword: "discriminator",
                type: "object",
                schemaType: "object",
                error,
                code(cxt) {
                    const { gen, data, schema, parentSchema, it } = cxt;
                    const { oneOf } = parentSchema;
                    if (!it.opts.discriminator) {
                        throw new Error("discriminator: requires discriminator option");
                    }
                    const tagName = schema.propertyName;
                    if (typeof tagName != "string")
                        throw new Error("discriminator: requires propertyName");
                    if (schema.mapping)
                        throw new Error("discriminator: mapping is not supported");
                    if (!oneOf)
                        throw new Error("discriminator: requires oneOf keyword");
                    const valid = gen.let("valid", false);
                    const tag = gen.const("tag", (0, codegen_1._)`${data}${(0, codegen_1.getProperty)(tagName)}`);
                    gen.if((0, codegen_1._)`typeof ${tag} == "string"`, () => validateMapping(), () => cxt.error(false, { discrError: types_1.DiscrError.Tag, tag, tagName }));
                    cxt.ok(valid);
                    function validateMapping() {
                        const mapping = getMapping();
                        gen.if(false);
                        for (const tagValue in mapping) {
                            gen.elseIf((0, codegen_1._)`${tag} === ${tagValue}`);
                            gen.assign(valid, applyTagSchema(mapping[tagValue]));
                        }
                        gen.else();
                        cxt.error(false, { discrError: types_1.DiscrError.Mapping, tag, tagName });
                        gen.endIf();
                    }
                    function applyTagSchema(schemaProp) {
                        const _valid = gen.name("valid");
                        const schCxt = cxt.subschema({ keyword: "oneOf", schemaProp }, _valid);
                        cxt.mergeEvaluated(schCxt, codegen_1.Name);
                        return _valid;
                    }
                    function getMapping() {
                        var _a;
                        const oneOfMapping = {};
                        const topRequired = hasRequired(parentSchema);
                        let tagRequired = true;
                        for (let i = 0; i < oneOf.length; i++) {
                            const sch = oneOf[i];
                            const propSch = (_a = sch.properties) === null || _a === void 0 ? void 0 : _a[tagName];
                            if (typeof propSch != "object") {
                                throw new Error(`discriminator: oneOf schemas must have "properties/${tagName}"`);
                            }
                            tagRequired = tagRequired && (topRequired || hasRequired(sch));
                            addMappings(propSch, i);
                        }
                        if (!tagRequired)
                            throw new Error(`discriminator: "${tagName}" must be required`);
                        return oneOfMapping;
                        function hasRequired({ required }) {
                            return Array.isArray(required) && required.includes(tagName);
                        }
                        function addMappings(sch, i) {
                            if (sch.const) {
                                addMapping(sch.const, i);
                            }
                            else if (sch.enum) {
                                for (const tagValue of sch.enum) {
                                    addMapping(tagValue, i);
                                }
                            }
                            else {
                                throw new Error(`discriminator: "properties/${tagName}" must have "const" or "enum"`);
                            }
                        }
                        function addMapping(tagValue, i) {
                            if (typeof tagValue != "string" || tagValue in oneOfMapping) {
                                throw new Error(`discriminator: "${tagName}" values must be unique strings`);
                            }
                            oneOfMapping[tagValue] = i;
                        }
                    }
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38, "../discriminator/types": 82 }], 82: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.DiscrError = void 0;
            var DiscrError;
            (function (DiscrError) {
                DiscrError["Tag"] = "tag";
                DiscrError["Mapping"] = "mapping";
            })(DiscrError = exports.DiscrError || (exports.DiscrError = {}));

        }, {}], 83: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const core_1 = require("./core");
            const validation_1 = require("./validation");
            const applicator_1 = require("./applicator");
            const format_1 = require("./format");
            const metadata_1 = require("./metadata");
            const draft7Vocabularies = [
                core_1.default,
                validation_1.default,
                (0, applicator_1.default)(),
                format_1.default,
                metadata_1.metadataVocabulary,
                metadata_1.contentVocabulary,
            ];
            exports.default = draft7Vocabularies;

        }, { "./applicator": 67, "./core": 79, "./format": 85, "./metadata": 86, "./validation": 89 }], 84: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("../../compile/codegen");
            const error = {
                message: ({ schemaCode }) => (0, codegen_1.str)`must match format "${schemaCode}"`,
                params: ({ schemaCode }) => (0, codegen_1._)`{format: ${schemaCode}}`,
            };
            const def = {
                keyword: "format",
                type: ["number", "string"],
                schemaType: "string",
                $data: true,
                error,
                code(cxt, ruleType) {
                    const { gen, data, $data, schema, schemaCode, it } = cxt;
                    const { opts, errSchemaPath, schemaEnv, self } = it;
                    if (!opts.validateFormats)
                        return;
                    if ($data)
                        validate$DataFormat();
                    else
                        validateFormat();
                    function validate$DataFormat() {
                        const fmts = gen.scopeValue("formats", {
                            ref: self.formats,
                            code: opts.code.formats,
                        });
                        const fDef = gen.const("fDef", (0, codegen_1._)`${fmts}[${schemaCode}]`);
                        const fType = gen.let("fType");
                        const format = gen.let("format");
                        // TODO simplify
                        gen.if((0, codegen_1._)`typeof ${fDef} == "object" && !(${fDef} instanceof RegExp)`, () => gen.assign(fType, (0, codegen_1._)`${fDef}.type || "string"`).assign(format, (0, codegen_1._)`${fDef}.validate`), () => gen.assign(fType, (0, codegen_1._)`"string"`).assign(format, fDef));
                        cxt.fail$data((0, codegen_1.or)(unknownFmt(), invalidFmt()));
                        function unknownFmt() {
                            if (opts.strictSchema === false)
                                return codegen_1.nil;
                            return (0, codegen_1._)`${schemaCode} && !${format}`;
                        }
                        function invalidFmt() {
                            const callFormat = schemaEnv.$async
                                ? (0, codegen_1._)`(${fDef}.async ? await ${format}(${data}) : ${format}(${data}))`
                                : (0, codegen_1._)`${format}(${data})`;
                            const validData = (0, codegen_1._)`(typeof ${format} == "function" ? ${callFormat} : ${format}.test(${data}))`;
                            return (0, codegen_1._)`${format} && ${format} !== true && ${fType} === ${ruleType} && !${validData}`;
                        }
                    }
                    function validateFormat() {
                        const formatDef = self.formats[schema];
                        if (!formatDef) {
                            unknownFormat();
                            return;
                        }
                        if (formatDef === true)
                            return;
                        const [fmtType, format, fmtRef] = getFormat(formatDef);
                        if (fmtType === ruleType)
                            cxt.pass(validCondition());
                        function unknownFormat() {
                            if (opts.strictSchema === false) {
                                self.logger.warn(unknownMsg());
                                return;
                            }
                            throw new Error(unknownMsg());
                            function unknownMsg() {
                                return `unknown format "${schema}" ignored in schema at path "${errSchemaPath}"`;
                            }
                        }
                        function getFormat(fmtDef) {
                            const code = fmtDef instanceof RegExp
                                ? (0, codegen_1.regexpCode)(fmtDef)
                                : opts.code.formats
                                    ? (0, codegen_1._)`${opts.code.formats}${(0, codegen_1.getProperty)(schema)}`
                                    : undefined;
                            const fmt = gen.scopeValue("formats", { key: schema, ref: fmtDef, code });
                            if (typeof fmtDef == "object" && !(fmtDef instanceof RegExp)) {
                                return [fmtDef.type || "string", fmtDef.validate, (0, codegen_1._)`${fmt}.validate`];
                            }
                            return ["string", fmtDef, fmt];
                        }
                        function validCondition() {
                            if (typeof formatDef == "object" && !(formatDef instanceof RegExp) && formatDef.async) {
                                if (!schemaEnv.$async)
                                    throw new Error("async format in sync schema");
                                return (0, codegen_1._)`await ${fmtRef}(${data})`;
                            }
                            return typeof format == "function" ? (0, codegen_1._)`${fmtRef}(${data})` : (0, codegen_1._)`${fmtRef}.test(${data})`;
                        }
                    }
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38 }], 85: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const format_1 = require("./format");
            const format = [format_1.default];
            exports.default = format;

        }, { "./format": 84 }], 86: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            exports.contentVocabulary = exports.metadataVocabulary = void 0;
            exports.metadataVocabulary = [
                "title",
                "description",
                "default",
                "deprecated",
                "readOnly",
                "writeOnly",
                "examples",
            ];
            exports.contentVocabulary = [
                "contentMediaType",
                "contentEncoding",
                "contentSchema",
            ];

        }, {}], 87: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("../../compile/codegen");
            const util_1 = require("../../compile/util");
            const equal_1 = require("../../runtime/equal");
            const error = {
                message: "must be equal to constant",
                params: ({ schemaCode }) => (0, codegen_1._)`{allowedValue: ${schemaCode}}`,
            };
            const def = {
                keyword: "const",
                $data: true,
                error,
                code(cxt) {
                    const { gen, data, $data, schemaCode, schema } = cxt;
                    if ($data || (schema && typeof schema == "object")) {
                        cxt.fail$data((0, codegen_1._)`!${(0, util_1.useFunc)(gen, equal_1.default)}(${data}, ${schemaCode})`);
                    }
                    else {
                        cxt.fail((0, codegen_1._)`${schema} !== ${data}`);
                    }
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/util": 46, "../../runtime/equal": 57 }], 88: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("../../compile/codegen");
            const util_1 = require("../../compile/util");
            const equal_1 = require("../../runtime/equal");
            const error = {
                message: "must be equal to one of the allowed values",
                params: ({ schemaCode }) => (0, codegen_1._)`{allowedValues: ${schemaCode}}`,
            };
            const def = {
                keyword: "enum",
                schemaType: "array",
                $data: true,
                error,
                code(cxt) {
                    const { gen, data, $data, schema, schemaCode, it } = cxt;
                    if (!$data && schema.length === 0)
                        throw new Error("enum must have non-empty array");
                    const useLoop = schema.length >= it.opts.loopEnum;
                    const eql = (0, util_1.useFunc)(gen, equal_1.default);
                    let valid;
                    if (useLoop || $data) {
                        valid = gen.let("valid");
                        cxt.block$data(valid, loopEnum);
                    }
                    else {
                        /* istanbul ignore if */
                        if (!Array.isArray(schema))
                            throw new Error("ajv implementation error");
                        const vSchema = gen.const("vSchema", schemaCode);
                        valid = (0, codegen_1.or)(...schema.map((_x, i) => equalCode(vSchema, i)));
                    }
                    cxt.pass(valid);
                    function loopEnum() {
                        gen.assign(valid, false);
                        gen.forOf("v", schemaCode, (v) => gen.if((0, codegen_1._)`${eql}(${data}, ${v})`, () => gen.assign(valid, true).break()));
                    }
                    function equalCode(vSchema, i) {
                        const sch = schema[i];
                        return typeof sch === "object" && sch !== null
                            ? (0, codegen_1._)`${eql}(${data}, ${vSchema}[${i}])`
                            : (0, codegen_1._)`${data} === ${sch}`;
                    }
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/util": 46, "../../runtime/equal": 57 }], 89: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const limitNumber_1 = require("./limitNumber");
            const multipleOf_1 = require("./multipleOf");
            const limitLength_1 = require("./limitLength");
            const pattern_1 = require("./pattern");
            const limitProperties_1 = require("./limitProperties");
            const required_1 = require("./required");
            const limitItems_1 = require("./limitItems");
            const uniqueItems_1 = require("./uniqueItems");
            const const_1 = require("./const");
            const enum_1 = require("./enum");
            const validation = [
                // number
                limitNumber_1.default,
                multipleOf_1.default,
                // string
                limitLength_1.default,
                pattern_1.default,
                // object
                limitProperties_1.default,
                required_1.default,
                // array
                limitItems_1.default,
                uniqueItems_1.default,
                // any
                { keyword: "type", schemaType: ["string", "array"] },
                { keyword: "nullable", schemaType: "boolean" },
                const_1.default,
                enum_1.default,
            ];
            exports.default = validation;

        }, { "./const": 87, "./enum": 88, "./limitItems": 90, "./limitLength": 91, "./limitNumber": 92, "./limitProperties": 93, "./multipleOf": 94, "./pattern": 95, "./required": 96, "./uniqueItems": 97 }], 90: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("../../compile/codegen");
            const error = {
                message({ keyword, schemaCode }) {
                    const comp = keyword === "maxItems" ? "more" : "fewer";
                    return (0, codegen_1.str)`must NOT have ${comp} than ${schemaCode} items`;
                },
                params: ({ schemaCode }) => (0, codegen_1._)`{limit: ${schemaCode}}`,
            };
            const def = {
                keyword: ["maxItems", "minItems"],
                type: "array",
                schemaType: "number",
                $data: true,
                error,
                code(cxt) {
                    const { keyword, data, schemaCode } = cxt;
                    const op = keyword === "maxItems" ? codegen_1.operators.GT : codegen_1.operators.LT;
                    cxt.fail$data((0, codegen_1._)`${data}.length ${op} ${schemaCode}`);
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38 }], 91: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("../../compile/codegen");
            const util_1 = require("../../compile/util");
            const ucs2length_1 = require("../../runtime/ucs2length");
            const error = {
                message({ keyword, schemaCode }) {
                    const comp = keyword === "maxLength" ? "more" : "fewer";
                    return (0, codegen_1.str)`must NOT have ${comp} than ${schemaCode} characters`;
                },
                params: ({ schemaCode }) => (0, codegen_1._)`{limit: ${schemaCode}}`,
            };
            const def = {
                keyword: ["maxLength", "minLength"],
                type: "string",
                schemaType: "number",
                $data: true,
                error,
                code(cxt) {
                    const { keyword, data, schemaCode, it } = cxt;
                    const op = keyword === "maxLength" ? codegen_1.operators.GT : codegen_1.operators.LT;
                    const len = it.opts.unicode === false ? (0, codegen_1._)`${data}.length` : (0, codegen_1._)`${(0, util_1.useFunc)(cxt.gen, ucs2length_1.default)}(${data})`;
                    cxt.fail$data((0, codegen_1._)`${len} ${op} ${schemaCode}`);
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/util": 46, "../../runtime/ucs2length": 58 }], 92: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("../../compile/codegen");
            const ops = codegen_1.operators;
            const KWDs = {
                maximum: { okStr: "<=", ok: ops.LTE, fail: ops.GT },
                minimum: { okStr: ">=", ok: ops.GTE, fail: ops.LT },
                exclusiveMaximum: { okStr: "<", ok: ops.LT, fail: ops.GTE },
                exclusiveMinimum: { okStr: ">", ok: ops.GT, fail: ops.LTE },
            };
            const error = {
                message: ({ keyword, schemaCode }) => (0, codegen_1.str)`must be ${KWDs[keyword].okStr} ${schemaCode}`,
                params: ({ keyword, schemaCode }) => (0, codegen_1._)`{comparison: ${KWDs[keyword].okStr}, limit: ${schemaCode}}`,
            };
            const def = {
                keyword: Object.keys(KWDs),
                type: "number",
                schemaType: "number",
                $data: true,
                error,
                code(cxt) {
                    const { keyword, data, schemaCode } = cxt;
                    cxt.fail$data((0, codegen_1._)`${data} ${KWDs[keyword].fail} ${schemaCode} || isNaN(${data})`);
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38 }], 93: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("../../compile/codegen");
            const error = {
                message({ keyword, schemaCode }) {
                    const comp = keyword === "maxProperties" ? "more" : "fewer";
                    return (0, codegen_1.str)`must NOT have ${comp} than ${schemaCode} items`;
                },
                params: ({ schemaCode }) => (0, codegen_1._)`{limit: ${schemaCode}}`,
            };
            const def = {
                keyword: ["maxProperties", "minProperties"],
                type: "object",
                schemaType: "number",
                $data: true,
                error,
                code(cxt) {
                    const { keyword, data, schemaCode } = cxt;
                    const op = keyword === "maxProperties" ? codegen_1.operators.GT : codegen_1.operators.LT;
                    cxt.fail$data((0, codegen_1._)`Object.keys(${data}).length ${op} ${schemaCode}`);
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38 }], 94: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const codegen_1 = require("../../compile/codegen");
            const error = {
                message: ({ schemaCode }) => (0, codegen_1.str)`must be multiple of ${schemaCode}`,
                params: ({ schemaCode }) => (0, codegen_1._)`{multipleOf: ${schemaCode}}`,
            };
            const def = {
                keyword: "multipleOf",
                type: "number",
                schemaType: "number",
                $data: true,
                error,
                code(cxt) {
                    const { gen, data, schemaCode, it } = cxt;
                    // const bdt = bad$DataType(schemaCode, <string>def.schemaType, $data)
                    const prec = it.opts.multipleOfPrecision;
                    const res = gen.let("res");
                    const invalid = prec
                        ? (0, codegen_1._)`Math.abs(Math.round(${res}) - ${res}) > 1e-${prec}`
                        : (0, codegen_1._)`${res} !== parseInt(${res})`;
                    cxt.fail$data((0, codegen_1._)`(${schemaCode} === 0 || (${res} = ${data}/${schemaCode}, ${invalid}))`);
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38 }], 95: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const code_1 = require("../code");
            const codegen_1 = require("../../compile/codegen");
            const error = {
                message: ({ schemaCode }) => (0, codegen_1.str)`must match pattern "${schemaCode}"`,
                params: ({ schemaCode }) => (0, codegen_1._)`{pattern: ${schemaCode}}`,
            };
            const def = {
                keyword: "pattern",
                type: "string",
                schemaType: "string",
                $data: true,
                error,
                code(cxt) {
                    const { data, $data, schema, schemaCode, it } = cxt;
                    // TODO regexp should be wrapped in try/catchs
                    const u = it.opts.unicodeRegExp ? "u" : "";
                    const regExp = $data ? (0, codegen_1._)`(new RegExp(${schemaCode}, ${u}))` : (0, code_1.usePattern)(cxt, schema);
                    cxt.fail$data((0, codegen_1._)`!${regExp}.test(${data})`);
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38, "../code": 77 }], 96: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const code_1 = require("../code");
            const codegen_1 = require("../../compile/codegen");
            const util_1 = require("../../compile/util");
            const error = {
                message: ({ params: { missingProperty } }) => (0, codegen_1.str)`must have required property '${missingProperty}'`,
                params: ({ params: { missingProperty } }) => (0, codegen_1._)`{missingProperty: ${missingProperty}}`,
            };
            const def = {
                keyword: "required",
                type: "object",
                schemaType: "array",
                $data: true,
                error,
                code(cxt) {
                    const { gen, schema, schemaCode, data, $data, it } = cxt;
                    const { opts } = it;
                    if (!$data && schema.length === 0)
                        return;
                    const useLoop = schema.length >= opts.loopRequired;
                    if (it.allErrors)
                        allErrorsMode();
                    else
                        exitOnErrorMode();
                    if (opts.strictRequired) {
                        const props = cxt.parentSchema.properties;
                        const { definedProperties } = cxt.it;
                        for (const requiredKey of schema) {
                            if ((props === null || props === void 0 ? void 0 : props[requiredKey]) === undefined && !definedProperties.has(requiredKey)) {
                                const schemaPath = it.schemaEnv.baseId + it.errSchemaPath;
                                const msg = `required property "${requiredKey}" is not defined at "${schemaPath}" (strictRequired)`;
                                (0, util_1.checkStrictMode)(it, msg, it.opts.strictRequired);
                            }
                        }
                    }
                    function allErrorsMode() {
                        if (useLoop || $data) {
                            cxt.block$data(codegen_1.nil, loopAllRequired);
                        }
                        else {
                            for (const prop of schema) {
                                (0, code_1.checkReportMissingProp)(cxt, prop);
                            }
                        }
                    }
                    function exitOnErrorMode() {
                        const missing = gen.let("missing");
                        if (useLoop || $data) {
                            const valid = gen.let("valid", true);
                            cxt.block$data(valid, () => loopUntilMissing(missing, valid));
                            cxt.ok(valid);
                        }
                        else {
                            gen.if((0, code_1.checkMissingProp)(cxt, schema, missing));
                            (0, code_1.reportMissingProp)(cxt, missing);
                            gen.else();
                        }
                    }
                    function loopAllRequired() {
                        gen.forOf("prop", schemaCode, (prop) => {
                            cxt.setParams({ missingProperty: prop });
                            gen.if((0, code_1.noPropertyInData)(gen, data, prop, opts.ownProperties), () => cxt.error());
                        });
                    }
                    function loopUntilMissing(missing, valid) {
                        cxt.setParams({ missingProperty: missing });
                        gen.forOf(missing, schemaCode, () => {
                            gen.assign(valid, (0, code_1.propertyInData)(gen, data, missing, opts.ownProperties));
                            gen.if((0, codegen_1.not)(valid), () => {
                                cxt.error();
                                gen.break();
                            });
                        }, codegen_1.nil);
                    }
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/util": 46, "../code": 77 }], 97: [function (require, module, exports) {
            "use strict";
            Object.defineProperty(exports, "__esModule", { value: true });
            const dataType_1 = require("../../compile/validate/dataType");
            const codegen_1 = require("../../compile/codegen");
            const util_1 = require("../../compile/util");
            const equal_1 = require("../../runtime/equal");
            const error = {
                message: ({ params: { i, j } }) => (0, codegen_1.str)`must NOT have duplicate items (items ## ${j} and ${i} are identical)`,
                params: ({ params: { i, j } }) => (0, codegen_1._)`{i: ${i}, j: ${j}}`,
            };
            const def = {
                keyword: "uniqueItems",
                type: "array",
                schemaType: "boolean",
                $data: true,
                error,
                code(cxt) {
                    const { gen, data, $data, schema, parentSchema, schemaCode, it } = cxt;
                    if (!$data && !schema)
                        return;
                    const valid = gen.let("valid");
                    const itemTypes = parentSchema.items ? (0, dataType_1.getSchemaTypes)(parentSchema.items) : [];
                    cxt.block$data(valid, validateUniqueItems, (0, codegen_1._)`${schemaCode} === false`);
                    cxt.ok(valid);
                    function validateUniqueItems() {
                        const i = gen.let("i", (0, codegen_1._)`${data}.length`);
                        const j = gen.let("j");
                        cxt.setParams({ i, j });
                        gen.assign(valid, true);
                        gen.if((0, codegen_1._)`${i} > 1`, () => (canOptimize() ? loopN : loopN2)(i, j));
                    }
                    function canOptimize() {
                        return itemTypes.length > 0 && !itemTypes.some((t) => t === "object" || t === "array");
                    }
                    function loopN(i, j) {
                        const item = gen.name("item");
                        const wrongType = (0, dataType_1.checkDataTypes)(itemTypes, item, it.opts.strictNumbers, dataType_1.DataType.Wrong);
                        const indices = gen.const("indices", (0, codegen_1._)`{}`);
                        gen.for((0, codegen_1._)`;${i}--;`, () => {
                            gen.let(item, (0, codegen_1._)`${data}[${i}]`);
                            gen.if(wrongType, (0, codegen_1._)`continue`);
                            if (itemTypes.length > 1)
                                gen.if((0, codegen_1._)`typeof ${item} == "string"`, (0, codegen_1._)`${item} += "_"`);
                            gen
                                .if((0, codegen_1._)`typeof ${indices}[${item}] == "number"`, () => {
                                    gen.assign(j, (0, codegen_1._)`${indices}[${item}]`);
                                    cxt.error();
                                    gen.assign(valid, false).break();
                                })
                                .code((0, codegen_1._)`${indices}[${item}] = ${i}`);
                        });
                    }
                    function loopN2(i, j) {
                        const eql = (0, util_1.useFunc)(gen, equal_1.default);
                        const outer = gen.name("outer");
                        gen.label(outer).for((0, codegen_1._)`;${i}--;`, () => gen.for((0, codegen_1._)`${j} = ${i}; ${j}--;`, () => gen.if((0, codegen_1._)`${eql}(${data}[${i}], ${data}[${j}])`, () => {
                            cxt.error();
                            gen.assign(valid, false).break(outer);
                        })));
                    }
                },
            };
            exports.default = def;

        }, { "../../compile/codegen": 38, "../../compile/util": 46, "../../compile/validate/dataType": 49, "../../runtime/equal": 57 }], 98: [function (require, module, exports) {
            (function (Buffer) {
                (function () {
                    var clone = (function () {
                        'use strict';

                        function _instanceof(obj, type) {
                            return type != null && obj instanceof type;
                        }

                        var nativeMap;
                        try {
                            nativeMap = Map;
                        } catch (_) {
                            // maybe a reference error because no `Map`. Give it a dummy value that no
                            // value will ever be an instanceof.
                            nativeMap = function () { };
                        }

                        var nativeSet;
                        try {
                            nativeSet = Set;
                        } catch (_) {
                            nativeSet = function () { };
                        }

                        var nativePromise;
                        try {
                            nativePromise = Promise;
                        } catch (_) {
                            nativePromise = function () { };
                        }

                        /**
                         * Clones (copies) an Object using deep copying.
                         *
                         * This function supports circular references by default, but if you are certain
                         * there are no circular references in your object, you can save some CPU time
                         * by calling clone(obj, false).
                         *
                         * Caution: if `circular` is false and `parent` contains circular references,
                         * your program may enter an infinite loop and crash.
                         *
                         * @param `parent` - the object to be cloned
                         * @param `circular` - set to true if the object to be cloned may contain
                         *    circular references. (optional - true by default)
                         * @param `depth` - set to a number if the object is only to be cloned to
                         *    a particular depth. (optional - defaults to Infinity)
                         * @param `prototype` - sets the prototype to be used when cloning an object.
                         *    (optional - defaults to parent prototype).
                         * @param `includeNonEnumerable` - set to true if the non-enumerable properties
                         *    should be cloned as well. Non-enumerable properties on the prototype
                         *    chain will be ignored. (optional - false by default)
                        */
                        function clone(parent, circular, depth, prototype, includeNonEnumerable) {
                            if (typeof circular === 'object') {
                                depth = circular.depth;
                                prototype = circular.prototype;
                                includeNonEnumerable = circular.includeNonEnumerable;
                                circular = circular.circular;
                            }
                            // maintain two arrays for circular references, where corresponding parents
                            // and children have the same index
                            var allParents = [];
                            var allChildren = [];

                            var useBuffer = typeof Buffer != 'undefined';

                            if (typeof circular == 'undefined')
                                circular = true;

                            if (typeof depth == 'undefined')
                                depth = Infinity;

                            // recurse this function so we don't reset allParents and allChildren
                            function _clone(parent, depth) {
                                // cloning null always returns null
                                if (parent === null)
                                    return null;

                                if (depth === 0)
                                    return parent;

                                var child;
                                var proto;
                                if (typeof parent != 'object') {
                                    return parent;
                                }

                                if (_instanceof(parent, nativeMap)) {
                                    child = new nativeMap();
                                } else if (_instanceof(parent, nativeSet)) {
                                    child = new nativeSet();
                                } else if (_instanceof(parent, nativePromise)) {
                                    child = new nativePromise(function (resolve, reject) {
                                        parent.then(function (value) {
                                            resolve(_clone(value, depth - 1));
                                        }, function (err) {
                                            reject(_clone(err, depth - 1));
                                        });
                                    });
                                } else if (clone.__isArray(parent)) {
                                    child = [];
                                } else if (clone.__isRegExp(parent)) {
                                    child = new RegExp(parent.source, __getRegExpFlags(parent));
                                    if (parent.lastIndex) child.lastIndex = parent.lastIndex;
                                } else if (clone.__isDate(parent)) {
                                    child = new Date(parent.getTime());
                                } else if (useBuffer && Buffer.isBuffer(parent)) {
                                    if (Buffer.allocUnsafe) {
                                        // Node.js >= 4.5.0
                                        child = Buffer.allocUnsafe(parent.length);
                                    } else {
                                        // Older Node.js versions
                                        child = new Buffer(parent.length);
                                    }
                                    parent.copy(child);
                                    return child;
                                } else if (_instanceof(parent, Error)) {
                                    child = Object.create(parent);
                                } else {
                                    if (typeof prototype == 'undefined') {
                                        proto = Object.getPrototypeOf(parent);
                                        child = Object.create(proto);
                                    }
                                    else {
                                        child = Object.create(prototype);
                                        proto = prototype;
                                    }
                                }

                                if (circular) {
                                    var index = allParents.indexOf(parent);

                                    if (index != -1) {
                                        return allChildren[index];
                                    }
                                    allParents.push(parent);
                                    allChildren.push(child);
                                }

                                if (_instanceof(parent, nativeMap)) {
                                    parent.forEach(function (value, key) {
                                        var keyChild = _clone(key, depth - 1);
                                        var valueChild = _clone(value, depth - 1);
                                        child.set(keyChild, valueChild);
                                    });
                                }
                                if (_instanceof(parent, nativeSet)) {
                                    parent.forEach(function (value) {
                                        var entryChild = _clone(value, depth - 1);
                                        child.add(entryChild);
                                    });
                                }

                                for (var i in parent) {
                                    var attrs;
                                    if (proto) {
                                        attrs = Object.getOwnPropertyDescriptor(proto, i);
                                    }

                                    if (attrs && attrs.set == null) {
                                        continue;
                                    }
                                    child[i] = _clone(parent[i], depth - 1);
                                }

                                if (Object.getOwnPropertySymbols) {
                                    var symbols = Object.getOwnPropertySymbols(parent);
                                    for (var i = 0; i < symbols.length; i++) {
                                        // Don't need to worry about cloning a symbol because it is a primitive,
                                        // like a number or string.
                                        var symbol = symbols[i];
                                        var descriptor = Object.getOwnPropertyDescriptor(parent, symbol);
                                        if (descriptor && !descriptor.enumerable && !includeNonEnumerable) {
                                            continue;
                                        }
                                        child[symbol] = _clone(parent[symbol], depth - 1);
                                        if (!descriptor.enumerable) {
                                            Object.defineProperty(child, symbol, {
                                                enumerable: false
                                            });
                                        }
                                    }
                                }

                                if (includeNonEnumerable) {
                                    var allPropertyNames = Object.getOwnPropertyNames(parent);
                                    for (var i = 0; i < allPropertyNames.length; i++) {
                                        var propertyName = allPropertyNames[i];
                                        var descriptor = Object.getOwnPropertyDescriptor(parent, propertyName);
                                        if (descriptor && descriptor.enumerable) {
                                            continue;
                                        }
                                        child[propertyName] = _clone(parent[propertyName], depth - 1);
                                        Object.defineProperty(child, propertyName, {
                                            enumerable: false
                                        });
                                    }
                                }

                                return child;
                            }

                            return _clone(parent, depth);
                        }

                        /**
                         * Simple flat clone using prototype, accepts only objects, usefull for property
                         * override on FLAT configuration object (no nested props).
                         *
                         * USE WITH CAUTION! This may not behave as you wish if you do not know how this
                         * works.
                         */
                        clone.clonePrototype = function clonePrototype(parent) {
                            if (parent === null)
                                return null;

                            var c = function () { };
                            c.prototype = parent;
                            return new c();
                        };

                        // private utility functions

                        function __objToStr(o) {
                            return Object.prototype.toString.call(o);
                        }
                        clone.__objToStr = __objToStr;

                        function __isDate(o) {
                            return typeof o === 'object' && __objToStr(o) === '[object Date]';
                        }
                        clone.__isDate = __isDate;

                        function __isArray(o) {
                            return typeof o === 'object' && __objToStr(o) === '[object Array]';
                        }
                        clone.__isArray = __isArray;

                        function __isRegExp(o) {
                            return typeof o === 'object' && __objToStr(o) === '[object RegExp]';
                        }
                        clone.__isRegExp = __isRegExp;

                        function __getRegExpFlags(re) {
                            var flags = '';
                            if (re.global) flags += 'g';
                            if (re.ignoreCase) flags += 'i';
                            if (re.multiline) flags += 'm';
                            return flags;
                        }
                        clone.__getRegExpFlags = __getRegExpFlags;

                        return clone;
                    })();

                    if (typeof module === 'object' && module.exports) {
                        module.exports = clone;
                    }

                }).call(this)
            }).call(this, require("buffer").Buffer)
        }, { "buffer": 3 }], 99: [function (require, module, exports) {
            'use strict';

            // do not edit .js files directly - edit src/index.jst



            module.exports = function equal(a, b) {
                if (a === b) return true;

                if (a && b && typeof a == 'object' && typeof b == 'object') {
                    if (a.constructor !== b.constructor) return false;

                    var length, i, keys;
                    if (Array.isArray(a)) {
                        length = a.length;
                        if (length != b.length) return false;
                        for (i = length; i-- !== 0;)
                            if (!equal(a[i], b[i])) return false;
                        return true;
                    }



                    if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
                    if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
                    if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();

                    keys = Object.keys(a);
                    length = keys.length;
                    if (length !== Object.keys(b).length) return false;

                    for (i = length; i-- !== 0;)
                        if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;

                    for (i = length; i-- !== 0;) {
                        var key = keys[i];

                        if (!equal(a[key], b[key])) return false;
                    }

                    return true;
                }

                // true if both NaN, false otherwise
                return a !== a && b !== b;
            };

        }, {}], 100: [function (require, module, exports) {
            'use strict';

            var traverse = module.exports = function (schema, opts, cb) {
                // Legacy support for v0.3.1 and earlier.
                if (typeof opts == 'function') {
                    cb = opts;
                    opts = {};
                }

                cb = opts.cb || cb;
                var pre = (typeof cb == 'function') ? cb : cb.pre || function () { };
                var post = cb.post || function () { };

                _traverse(opts, pre, post, schema, '', schema);
            };


            traverse.keywords = {
                additionalItems: true,
                items: true,
                contains: true,
                additionalProperties: true,
                propertyNames: true,
                not: true,
                if: true,
                then: true,
                else: true
            };

            traverse.arrayKeywords = {
                items: true,
                allOf: true,
                anyOf: true,
                oneOf: true
            };

            traverse.propsKeywords = {
                $defs: true,
                definitions: true,
                properties: true,
                patternProperties: true,
                dependencies: true
            };

            traverse.skipKeywords = {
                default: true,
                enum: true,
                const: true,
                required: true,
                maximum: true,
                minimum: true,
                exclusiveMaximum: true,
                exclusiveMinimum: true,
                multipleOf: true,
                maxLength: true,
                minLength: true,
                pattern: true,
                format: true,
                maxItems: true,
                minItems: true,
                uniqueItems: true,
                maxProperties: true,
                minProperties: true
            };


            function _traverse(opts, pre, post, schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex) {
                if (schema && typeof schema == 'object' && !Array.isArray(schema)) {
                    pre(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
                    for (var key in schema) {
                        var sch = schema[key];
                        if (Array.isArray(sch)) {
                            if (key in traverse.arrayKeywords) {
                                for (var i = 0; i < sch.length; i++)
                                    _traverse(opts, pre, post, sch[i], jsonPtr + '/' + key + '/' + i, rootSchema, jsonPtr, key, schema, i);
                            }
                        } else if (key in traverse.propsKeywords) {
                            if (sch && typeof sch == 'object') {
                                for (var prop in sch)
                                    _traverse(opts, pre, post, sch[prop], jsonPtr + '/' + key + '/' + escapeJsonPtr(prop), rootSchema, jsonPtr, key, schema, prop);
                            }
                        } else if (key in traverse.keywords || (opts.allKeys && !(key in traverse.skipKeywords))) {
                            _traverse(opts, pre, post, sch, jsonPtr + '/' + key, rootSchema, jsonPtr, key, schema);
                        }
                    }
                    post(schema, jsonPtr, rootSchema, parentJsonPtr, parentKeyword, parentSchema, keyIndex);
                }
            }


            function escapeJsonPtr(str) {
                return str.replace(/~/g, '~0').replace(/\//g, '~1');
            }

        }, {}], 101: [function (require, module, exports) {
            (function (global, factory) {
                typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
                    typeof define === 'function' && define.amd ? define(factory) :
                        (global.JSON5 = factory());
            }(this, (function () {
                'use strict';

                function createCommonjsModule(fn, module) {
                    return module = { exports: {} }, fn(module, module.exports), module.exports;
                }

                var _global = createCommonjsModule(function (module) {
                    // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
                    var global = module.exports = typeof window != 'undefined' && window.Math == Math
                        ? window : typeof self != 'undefined' && self.Math == Math ? self
                            // eslint-disable-next-line no-new-func
                            : Function('return this')();
                    if (typeof __g == 'number') { __g = global; } // eslint-disable-line no-undef
                });

                var _core = createCommonjsModule(function (module) {
                    var core = module.exports = { version: '2.6.5' };
                    if (typeof __e == 'number') { __e = core; } // eslint-disable-line no-undef
                });
                var _core_1 = _core.version;

                var _isObject = function (it) {
                    return typeof it === 'object' ? it !== null : typeof it === 'function';
                };

                var _anObject = function (it) {
                    if (!_isObject(it)) { throw TypeError(it + ' is not an object!'); }
                    return it;
                };

                var _fails = function (exec) {
                    try {
                        return !!exec();
                    } catch (e) {
                        return true;
                    }
                };

                // Thank's IE8 for his funny defineProperty
                var _descriptors = !_fails(function () {
                    return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a != 7;
                });

                var document = _global.document;
                // typeof document.createElement is 'object' in old IE
                var is = _isObject(document) && _isObject(document.createElement);
                var _domCreate = function (it) {
                    return is ? document.createElement(it) : {};
                };

                var _ie8DomDefine = !_descriptors && !_fails(function () {
                    return Object.defineProperty(_domCreate('div'), 'a', { get: function () { return 7; } }).a != 7;
                });

                // 7.1.1 ToPrimitive(input [, PreferredType])

                // instead of the ES6 spec version, we didn't implement @@toPrimitive case
                // and the second argument - flag - preferred type is a string
                var _toPrimitive = function (it, S) {
                    if (!_isObject(it)) { return it; }
                    var fn, val;
                    if (S && typeof (fn = it.toString) == 'function' && !_isObject(val = fn.call(it))) { return val; }
                    if (typeof (fn = it.valueOf) == 'function' && !_isObject(val = fn.call(it))) { return val; }
                    if (!S && typeof (fn = it.toString) == 'function' && !_isObject(val = fn.call(it))) { return val; }
                    throw TypeError("Can't convert object to primitive value");
                };

                var dP = Object.defineProperty;

                var f = _descriptors ? Object.defineProperty : function defineProperty(O, P, Attributes) {
                    _anObject(O);
                    P = _toPrimitive(P, true);
                    _anObject(Attributes);
                    if (_ie8DomDefine) {
                        try {
                            return dP(O, P, Attributes);
                        } catch (e) { /* empty */ }
                    }
                    if ('get' in Attributes || 'set' in Attributes) { throw TypeError('Accessors not supported!'); }
                    if ('value' in Attributes) { O[P] = Attributes.value; }
                    return O;
                };

                var _objectDp = {
                    f: f
                };

                var _propertyDesc = function (bitmap, value) {
                    return {
                        enumerable: !(bitmap & 1),
                        configurable: !(bitmap & 2),
                        writable: !(bitmap & 4),
                        value: value
                    };
                };

                var _hide = _descriptors ? function (object, key, value) {
                    return _objectDp.f(object, key, _propertyDesc(1, value));
                } : function (object, key, value) {
                    object[key] = value;
                    return object;
                };

                var hasOwnProperty = {}.hasOwnProperty;
                var _has = function (it, key) {
                    return hasOwnProperty.call(it, key);
                };

                var id = 0;
                var px = Math.random();
                var _uid = function (key) {
                    return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36));
                };

                var _library = false;

                var _shared = createCommonjsModule(function (module) {
                    var SHARED = '__core-js_shared__';
                    var store = _global[SHARED] || (_global[SHARED] = {});

                    (module.exports = function (key, value) {
                        return store[key] || (store[key] = value !== undefined ? value : {});
                    })('versions', []).push({
                        version: _core.version,
                        mode: _library ? 'pure' : 'global',
                        copyright: '© 2019 Denis Pushkarev (zloirock.ru)'
                    });
                });

                var _functionToString = _shared('native-function-to-string', Function.toString);

                var _redefine = createCommonjsModule(function (module) {
                    var SRC = _uid('src');

                    var TO_STRING = 'toString';
                    var TPL = ('' + _functionToString).split(TO_STRING);

                    _core.inspectSource = function (it) {
                        return _functionToString.call(it);
                    };

                    (module.exports = function (O, key, val, safe) {
                        var isFunction = typeof val == 'function';
                        if (isFunction) { _has(val, 'name') || _hide(val, 'name', key); }
                        if (O[key] === val) { return; }
                        if (isFunction) { _has(val, SRC) || _hide(val, SRC, O[key] ? '' + O[key] : TPL.join(String(key))); }
                        if (O === _global) {
                            O[key] = val;
                        } else if (!safe) {
                            delete O[key];
                            _hide(O, key, val);
                        } else if (O[key]) {
                            O[key] = val;
                        } else {
                            _hide(O, key, val);
                        }
                        // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
                    })(Function.prototype, TO_STRING, function toString() {
                        return typeof this == 'function' && this[SRC] || _functionToString.call(this);
                    });
                });

                var _aFunction = function (it) {
                    if (typeof it != 'function') { throw TypeError(it + ' is not a function!'); }
                    return it;
                };

                // optional / simple context binding

                var _ctx = function (fn, that, length) {
                    _aFunction(fn);
                    if (that === undefined) { return fn; }
                    switch (length) {
                        case 1: return function (a) {
                            return fn.call(that, a);
                        };
                        case 2: return function (a, b) {
                            return fn.call(that, a, b);
                        };
                        case 3: return function (a, b, c) {
                            return fn.call(that, a, b, c);
                        };
                    }
                    return function (/* ...args */) {
                        return fn.apply(that, arguments);
                    };
                };

                var PROTOTYPE = 'prototype';

                var $export = function (type, name, source) {
                    var IS_FORCED = type & $export.F;
                    var IS_GLOBAL = type & $export.G;
                    var IS_STATIC = type & $export.S;
                    var IS_PROTO = type & $export.P;
                    var IS_BIND = type & $export.B;
                    var target = IS_GLOBAL ? _global : IS_STATIC ? _global[name] || (_global[name] = {}) : (_global[name] || {})[PROTOTYPE];
                    var exports = IS_GLOBAL ? _core : _core[name] || (_core[name] = {});
                    var expProto = exports[PROTOTYPE] || (exports[PROTOTYPE] = {});
                    var key, own, out, exp;
                    if (IS_GLOBAL) { source = name; }
                    for (key in source) {
                        // contains in native
                        own = !IS_FORCED && target && target[key] !== undefined;
                        // export native or passed
                        out = (own ? target : source)[key];
                        // bind timers to global for call from export context
                        exp = IS_BIND && own ? _ctx(out, _global) : IS_PROTO && typeof out == 'function' ? _ctx(Function.call, out) : out;
                        // extend global
                        if (target) { _redefine(target, key, out, type & $export.U); }
                        // export
                        if (exports[key] != out) { _hide(exports, key, exp); }
                        if (IS_PROTO && expProto[key] != out) { expProto[key] = out; }
                    }
                };
                _global.core = _core;
                // type bitmap
                $export.F = 1;   // forced
                $export.G = 2;   // global
                $export.S = 4;   // static
                $export.P = 8;   // proto
                $export.B = 16;  // bind
                $export.W = 32;  // wrap
                $export.U = 64;  // safe
                $export.R = 128; // real proto method for `library`
                var _export = $export;

                // 7.1.4 ToInteger
                var ceil = Math.ceil;
                var floor = Math.floor;
                var _toInteger = function (it) {
                    return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it);
                };

                // 7.2.1 RequireObjectCoercible(argument)
                var _defined = function (it) {
                    if (it == undefined) { throw TypeError("Can't call method on  " + it); }
                    return it;
                };

                // true  -> String#at
                // false -> String#codePointAt
                var _stringAt = function (TO_STRING) {
                    return function (that, pos) {
                        var s = String(_defined(that));
                        var i = _toInteger(pos);
                        var l = s.length;
                        var a, b;
                        if (i < 0 || i >= l) { return TO_STRING ? '' : undefined; }
                        a = s.charCodeAt(i);
                        return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff
                            ? TO_STRING ? s.charAt(i) : a
                            : TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000;
                    };
                };

                var $at = _stringAt(false);
                _export(_export.P, 'String', {
                    // 21.1.3.3 String.prototype.codePointAt(pos)
                    codePointAt: function codePointAt(pos) {
                        return $at(this, pos);
                    }
                });

                var codePointAt = _core.String.codePointAt;

                var max = Math.max;
                var min = Math.min;
                var _toAbsoluteIndex = function (index, length) {
                    index = _toInteger(index);
                    return index < 0 ? max(index + length, 0) : min(index, length);
                };

                var fromCharCode = String.fromCharCode;
                var $fromCodePoint = String.fromCodePoint;

                // length should be 1, old FF problem
                _export(_export.S + _export.F * (!!$fromCodePoint && $fromCodePoint.length != 1), 'String', {
                    // 21.1.2.2 String.fromCodePoint(...codePoints)
                    fromCodePoint: function fromCodePoint(x) {
                        var arguments$1 = arguments;
                        // eslint-disable-line no-unused-vars
                        var res = [];
                        var aLen = arguments.length;
                        var i = 0;
                        var code;
                        while (aLen > i) {
                            code = +arguments$1[i++];
                            if (_toAbsoluteIndex(code, 0x10ffff) !== code) { throw RangeError(code + ' is not a valid code point'); }
                            res.push(code < 0x10000
                                ? fromCharCode(code)
                                : fromCharCode(((code -= 0x10000) >> 10) + 0xd800, code % 0x400 + 0xdc00)
                            );
                        } return res.join('');
                    }
                });

                var fromCodePoint = _core.String.fromCodePoint;

                // This is a generated file. Do not edit.
                var Space_Separator = /[\u1680\u2000-\u200A\u202F\u205F\u3000]/;
                var ID_Start = /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]/;
                var ID_Continue = /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u08D4-\u08E1\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u09FC\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9-\u0AFF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C80-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D00-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D54-\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1CD0-\u1CD2\u1CD4-\u1CF9\u1D00-\u1DF9\u1DFB-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C5\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE3E\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC00-\uDC4A\uDC50-\uDC59\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDE00-\uDE3E\uDE47\uDE50-\uDE83\uDE86-\uDE99\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC36\uDC38-\uDC40\uDC50-\uDC59\uDC72-\uDC8F\uDC92-\uDCA7\uDCA9-\uDCB6\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD36\uDD3A\uDD3C\uDD3D\uDD3F-\uDD47\uDD50-\uDD59]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD838[\uDC00-\uDC06\uDC08-\uDC18\uDC1B-\uDC21\uDC23\uDC24\uDC26-\uDC2A]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6\uDD00-\uDD4A\uDD50-\uDD59]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/;

                var unicode = {
                    Space_Separator: Space_Separator,
                    ID_Start: ID_Start,
                    ID_Continue: ID_Continue
                };

                var util = {
                    isSpaceSeparator: function isSpaceSeparator(c) {
                        return typeof c === 'string' && unicode.Space_Separator.test(c)
                    },

                    isIdStartChar: function isIdStartChar(c) {
                        return typeof c === 'string' && (
                            (c >= 'a' && c <= 'z') ||
                            (c >= 'A' && c <= 'Z') ||
                            (c === '$') || (c === '_') ||
                            unicode.ID_Start.test(c)
                        )
                    },

                    isIdContinueChar: function isIdContinueChar(c) {
                        return typeof c === 'string' && (
                            (c >= 'a' && c <= 'z') ||
                            (c >= 'A' && c <= 'Z') ||
                            (c >= '0' && c <= '9') ||
                            (c === '$') || (c === '_') ||
                            (c === '\u200C') || (c === '\u200D') ||
                            unicode.ID_Continue.test(c)
                        )
                    },

                    isDigit: function isDigit(c) {
                        return typeof c === 'string' && /[0-9]/.test(c)
                    },

                    isHexDigit: function isHexDigit(c) {
                        return typeof c === 'string' && /[0-9A-Fa-f]/.test(c)
                    },
                };

                var source;
                var parseState;
                var stack;
                var pos;
                var line;
                var column;
                var token;
                var key;
                var root;

                var parse = function parse(text, reviver) {
                    source = String(text);
                    parseState = 'start';
                    stack = [];
                    pos = 0;
                    line = 1;
                    column = 0;
                    token = undefined;
                    key = undefined;
                    root = undefined;

                    do {
                        token = lex();

                        // This code is unreachable.
                        // if (!parseStates[parseState]) {
                        //     throw invalidParseState()
                        // }

                        parseStates[parseState]();
                    } while (token.type !== 'eof')

                    if (typeof reviver === 'function') {
                        return internalize({ '': root }, '', reviver)
                    }

                    return root
                };

                function internalize(holder, name, reviver) {
                    var value = holder[name];
                    if (value != null && typeof value === 'object') {
                        for (var key in value) {
                            var replacement = internalize(value, key, reviver);
                            if (replacement === undefined) {
                                delete value[key];
                            } else {
                                value[key] = replacement;
                            }
                        }
                    }

                    return reviver.call(holder, name, value)
                }

                var lexState;
                var buffer;
                var doubleQuote;
                var sign;
                var c;

                function lex() {
                    lexState = 'default';
                    buffer = '';
                    doubleQuote = false;
                    sign = 1;

                    for (; ;) {
                        c = peek();

                        // This code is unreachable.
                        // if (!lexStates[lexState]) {
                        //     throw invalidLexState(lexState)
                        // }

                        var token = lexStates[lexState]();
                        if (token) {
                            return token
                        }
                    }
                }

                function peek() {
                    if (source[pos]) {
                        return String.fromCodePoint(source.codePointAt(pos))
                    }
                }

                function read() {
                    var c = peek();

                    if (c === '\n') {
                        line++;
                        column = 0;
                    } else if (c) {
                        column += c.length;
                    } else {
                        column++;
                    }

                    if (c) {
                        pos += c.length;
                    }

                    return c
                }

                var lexStates = {
                    default: function default$1() {
                        switch (c) {
                            case '\t':
                            case '\v':
                            case '\f':
                            case ' ':
                            case '\u00A0':
                            case '\uFEFF':
                            case '\n':
                            case '\r':
                            case '\u2028':
                            case '\u2029':
                                read();
                                return

                            case '/':
                                read();
                                lexState = 'comment';
                                return

                            case undefined:
                                read();
                                return newToken('eof')
                        }

                        if (util.isSpaceSeparator(c)) {
                            read();
                            return
                        }

                        // This code is unreachable.
                        // if (!lexStates[parseState]) {
                        //     throw invalidLexState(parseState)
                        // }

                        return lexStates[parseState]()
                    },

                    comment: function comment() {
                        switch (c) {
                            case '*':
                                read();
                                lexState = 'multiLineComment';
                                return

                            case '/':
                                read();
                                lexState = 'singleLineComment';
                                return
                        }

                        throw invalidChar(read())
                    },

                    multiLineComment: function multiLineComment() {
                        switch (c) {
                            case '*':
                                read();
                                lexState = 'multiLineCommentAsterisk';
                                return

                            case undefined:
                                throw invalidChar(read())
                        }

                        read();
                    },

                    multiLineCommentAsterisk: function multiLineCommentAsterisk() {
                        switch (c) {
                            case '*':
                                read();
                                return

                            case '/':
                                read();
                                lexState = 'default';
                                return

                            case undefined:
                                throw invalidChar(read())
                        }

                        read();
                        lexState = 'multiLineComment';
                    },

                    singleLineComment: function singleLineComment() {
                        switch (c) {
                            case '\n':
                            case '\r':
                            case '\u2028':
                            case '\u2029':
                                read();
                                lexState = 'default';
                                return

                            case undefined:
                                read();
                                return newToken('eof')
                        }

                        read();
                    },

                    value: function value() {
                        switch (c) {
                            case '{':
                            case '[':
                                return newToken('punctuator', read())

                            case 'n':
                                read();
                                literal('ull');
                                return newToken('null', null)

                            case 't':
                                read();
                                literal('rue');
                                return newToken('boolean', true)

                            case 'f':
                                read();
                                literal('alse');
                                return newToken('boolean', false)

                            case '-':
                            case '+':
                                if (read() === '-') {
                                    sign = -1;
                                }

                                lexState = 'sign';
                                return

                            case '.':
                                buffer = read();
                                lexState = 'decimalPointLeading';
                                return

                            case '0':
                                buffer = read();
                                lexState = 'zero';
                                return

                            case '1':
                            case '2':
                            case '3':
                            case '4':
                            case '5':
                            case '6':
                            case '7':
                            case '8':
                            case '9':
                                buffer = read();
                                lexState = 'decimalInteger';
                                return

                            case 'I':
                                read();
                                literal('nfinity');
                                return newToken('numeric', Infinity)

                            case 'N':
                                read();
                                literal('aN');
                                return newToken('numeric', NaN)

                            case '"':
                            case "'":
                                doubleQuote = (read() === '"');
                                buffer = '';
                                lexState = 'string';
                                return
                        }

                        throw invalidChar(read())
                    },

                    identifierNameStartEscape: function identifierNameStartEscape() {
                        if (c !== 'u') {
                            throw invalidChar(read())
                        }

                        read();
                        var u = unicodeEscape();
                        switch (u) {
                            case '$':
                            case '_':
                                break

                            default:
                                if (!util.isIdStartChar(u)) {
                                    throw invalidIdentifier()
                                }

                                break
                        }

                        buffer += u;
                        lexState = 'identifierName';
                    },

                    identifierName: function identifierName() {
                        switch (c) {
                            case '$':
                            case '_':
                            case '\u200C':
                            case '\u200D':
                                buffer += read();
                                return

                            case '\\':
                                read();
                                lexState = 'identifierNameEscape';
                                return
                        }

                        if (util.isIdContinueChar(c)) {
                            buffer += read();
                            return
                        }

                        return newToken('identifier', buffer)
                    },

                    identifierNameEscape: function identifierNameEscape() {
                        if (c !== 'u') {
                            throw invalidChar(read())
                        }

                        read();
                        var u = unicodeEscape();
                        switch (u) {
                            case '$':
                            case '_':
                            case '\u200C':
                            case '\u200D':
                                break

                            default:
                                if (!util.isIdContinueChar(u)) {
                                    throw invalidIdentifier()
                                }

                                break
                        }

                        buffer += u;
                        lexState = 'identifierName';
                    },

                    sign: function sign$1() {
                        switch (c) {
                            case '.':
                                buffer = read();
                                lexState = 'decimalPointLeading';
                                return

                            case '0':
                                buffer = read();
                                lexState = 'zero';
                                return

                            case '1':
                            case '2':
                            case '3':
                            case '4':
                            case '5':
                            case '6':
                            case '7':
                            case '8':
                            case '9':
                                buffer = read();
                                lexState = 'decimalInteger';
                                return

                            case 'I':
                                read();
                                literal('nfinity');
                                return newToken('numeric', sign * Infinity)

                            case 'N':
                                read();
                                literal('aN');
                                return newToken('numeric', NaN)
                        }

                        throw invalidChar(read())
                    },

                    zero: function zero() {
                        switch (c) {
                            case '.':
                                buffer += read();
                                lexState = 'decimalPoint';
                                return

                            case 'e':
                            case 'E':
                                buffer += read();
                                lexState = 'decimalExponent';
                                return

                            case 'x':
                            case 'X':
                                buffer += read();
                                lexState = 'hexadecimal';
                                return
                        }

                        return newToken('numeric', sign * 0)
                    },

                    decimalInteger: function decimalInteger() {
                        switch (c) {
                            case '.':
                                buffer += read();
                                lexState = 'decimalPoint';
                                return

                            case 'e':
                            case 'E':
                                buffer += read();
                                lexState = 'decimalExponent';
                                return
                        }

                        if (util.isDigit(c)) {
                            buffer += read();
                            return
                        }

                        return newToken('numeric', sign * Number(buffer))
                    },

                    decimalPointLeading: function decimalPointLeading() {
                        if (util.isDigit(c)) {
                            buffer += read();
                            lexState = 'decimalFraction';
                            return
                        }

                        throw invalidChar(read())
                    },

                    decimalPoint: function decimalPoint() {
                        switch (c) {
                            case 'e':
                            case 'E':
                                buffer += read();
                                lexState = 'decimalExponent';
                                return
                        }

                        if (util.isDigit(c)) {
                            buffer += read();
                            lexState = 'decimalFraction';
                            return
                        }

                        return newToken('numeric', sign * Number(buffer))
                    },

                    decimalFraction: function decimalFraction() {
                        switch (c) {
                            case 'e':
                            case 'E':
                                buffer += read();
                                lexState = 'decimalExponent';
                                return
                        }

                        if (util.isDigit(c)) {
                            buffer += read();
                            return
                        }

                        return newToken('numeric', sign * Number(buffer))
                    },

                    decimalExponent: function decimalExponent() {
                        switch (c) {
                            case '+':
                            case '-':
                                buffer += read();
                                lexState = 'decimalExponentSign';
                                return
                        }

                        if (util.isDigit(c)) {
                            buffer += read();
                            lexState = 'decimalExponentInteger';
                            return
                        }

                        throw invalidChar(read())
                    },

                    decimalExponentSign: function decimalExponentSign() {
                        if (util.isDigit(c)) {
                            buffer += read();
                            lexState = 'decimalExponentInteger';
                            return
                        }

                        throw invalidChar(read())
                    },

                    decimalExponentInteger: function decimalExponentInteger() {
                        if (util.isDigit(c)) {
                            buffer += read();
                            return
                        }

                        return newToken('numeric', sign * Number(buffer))
                    },

                    hexadecimal: function hexadecimal() {
                        if (util.isHexDigit(c)) {
                            buffer += read();
                            lexState = 'hexadecimalInteger';
                            return
                        }

                        throw invalidChar(read())
                    },

                    hexadecimalInteger: function hexadecimalInteger() {
                        if (util.isHexDigit(c)) {
                            buffer += read();
                            return
                        }

                        return newToken('numeric', sign * Number(buffer))
                    },

                    string: function string() {
                        switch (c) {
                            case '\\':
                                read();
                                buffer += escape();
                                return

                            case '"':
                                if (doubleQuote) {
                                    read();
                                    return newToken('string', buffer)
                                }

                                buffer += read();
                                return

                            case "'":
                                if (!doubleQuote) {
                                    read();
                                    return newToken('string', buffer)
                                }

                                buffer += read();
                                return

                            case '\n':
                            case '\r':
                                throw invalidChar(read())

                            case '\u2028':
                            case '\u2029':
                                separatorChar(c);
                                break

                            case undefined:
                                throw invalidChar(read())
                        }

                        buffer += read();
                    },

                    start: function start() {
                        switch (c) {
                            case '{':
                            case '[':
                                return newToken('punctuator', read())

                            // This code is unreachable since the default lexState handles eof.
                            // case undefined:
                            //     return newToken('eof')
                        }

                        lexState = 'value';
                    },

                    beforePropertyName: function beforePropertyName() {
                        switch (c) {
                            case '$':
                            case '_':
                                buffer = read();
                                lexState = 'identifierName';
                                return

                            case '\\':
                                read();
                                lexState = 'identifierNameStartEscape';
                                return

                            case '}':
                                return newToken('punctuator', read())

                            case '"':
                            case "'":
                                doubleQuote = (read() === '"');
                                lexState = 'string';
                                return
                        }

                        if (util.isIdStartChar(c)) {
                            buffer += read();
                            lexState = 'identifierName';
                            return
                        }

                        throw invalidChar(read())
                    },

                    afterPropertyName: function afterPropertyName() {
                        if (c === ':') {
                            return newToken('punctuator', read())
                        }

                        throw invalidChar(read())
                    },

                    beforePropertyValue: function beforePropertyValue() {
                        lexState = 'value';
                    },

                    afterPropertyValue: function afterPropertyValue() {
                        switch (c) {
                            case ',':
                            case '}':
                                return newToken('punctuator', read())
                        }

                        throw invalidChar(read())
                    },

                    beforeArrayValue: function beforeArrayValue() {
                        if (c === ']') {
                            return newToken('punctuator', read())
                        }

                        lexState = 'value';
                    },

                    afterArrayValue: function afterArrayValue() {
                        switch (c) {
                            case ',':
                            case ']':
                                return newToken('punctuator', read())
                        }

                        throw invalidChar(read())
                    },

                    end: function end() {
                        // This code is unreachable since it's handled by the default lexState.
                        // if (c === undefined) {
                        //     read()
                        //     return newToken('eof')
                        // }

                        throw invalidChar(read())
                    },
                };

                function newToken(type, value) {
                    return {
                        type: type,
                        value: value,
                        line: line,
                        column: column,
                    }
                }

                function literal(s) {
                    for (var i = 0, list = s; i < list.length; i += 1) {
                        var c = list[i];

                        var p = peek();

                        if (p !== c) {
                            throw invalidChar(read())
                        }

                        read();
                    }
                }

                function escape() {
                    var c = peek();
                    switch (c) {
                        case 'b':
                            read();
                            return '\b'

                        case 'f':
                            read();
                            return '\f'

                        case 'n':
                            read();
                            return '\n'

                        case 'r':
                            read();
                            return '\r'

                        case 't':
                            read();
                            return '\t'

                        case 'v':
                            read();
                            return '\v'

                        case '0':
                            read();
                            if (util.isDigit(peek())) {
                                throw invalidChar(read())
                            }

                            return '\0'

                        case 'x':
                            read();
                            return hexEscape()

                        case 'u':
                            read();
                            return unicodeEscape()

                        case '\n':
                        case '\u2028':
                        case '\u2029':
                            read();
                            return ''

                        case '\r':
                            read();
                            if (peek() === '\n') {
                                read();
                            }

                            return ''

                        case '1':
                        case '2':
                        case '3':
                        case '4':
                        case '5':
                        case '6':
                        case '7':
                        case '8':
                        case '9':
                            throw invalidChar(read())

                        case undefined:
                            throw invalidChar(read())
                    }

                    return read()
                }

                function hexEscape() {
                    var buffer = '';
                    var c = peek();

                    if (!util.isHexDigit(c)) {
                        throw invalidChar(read())
                    }

                    buffer += read();

                    c = peek();
                    if (!util.isHexDigit(c)) {
                        throw invalidChar(read())
                    }

                    buffer += read();

                    return String.fromCodePoint(parseInt(buffer, 16))
                }

                function unicodeEscape() {
                    var buffer = '';
                    var count = 4;

                    while (count-- > 0) {
                        var c = peek();
                        if (!util.isHexDigit(c)) {
                            throw invalidChar(read())
                        }

                        buffer += read();
                    }

                    return String.fromCodePoint(parseInt(buffer, 16))
                }

                var parseStates = {
                    start: function start() {
                        if (token.type === 'eof') {
                            throw invalidEOF()
                        }

                        push();
                    },

                    beforePropertyName: function beforePropertyName() {
                        switch (token.type) {
                            case 'identifier':
                            case 'string':
                                key = token.value;
                                parseState = 'afterPropertyName';
                                return

                            case 'punctuator':
                                // This code is unreachable since it's handled by the lexState.
                                // if (token.value !== '}') {
                                //     throw invalidToken()
                                // }

                                pop();
                                return

                            case 'eof':
                                throw invalidEOF()
                        }

                        // This code is unreachable since it's handled by the lexState.
                        // throw invalidToken()
                    },

                    afterPropertyName: function afterPropertyName() {
                        // This code is unreachable since it's handled by the lexState.
                        // if (token.type !== 'punctuator' || token.value !== ':') {
                        //     throw invalidToken()
                        // }

                        if (token.type === 'eof') {
                            throw invalidEOF()
                        }

                        parseState = 'beforePropertyValue';
                    },

                    beforePropertyValue: function beforePropertyValue() {
                        if (token.type === 'eof') {
                            throw invalidEOF()
                        }

                        push();
                    },

                    beforeArrayValue: function beforeArrayValue() {
                        if (token.type === 'eof') {
                            throw invalidEOF()
                        }

                        if (token.type === 'punctuator' && token.value === ']') {
                            pop();
                            return
                        }

                        push();
                    },

                    afterPropertyValue: function afterPropertyValue() {
                        // This code is unreachable since it's handled by the lexState.
                        // if (token.type !== 'punctuator') {
                        //     throw invalidToken()
                        // }

                        if (token.type === 'eof') {
                            throw invalidEOF()
                        }

                        switch (token.value) {
                            case ',':
                                parseState = 'beforePropertyName';
                                return

                            case '}':
                                pop();
                        }

                        // This code is unreachable since it's handled by the lexState.
                        // throw invalidToken()
                    },

                    afterArrayValue: function afterArrayValue() {
                        // This code is unreachable since it's handled by the lexState.
                        // if (token.type !== 'punctuator') {
                        //     throw invalidToken()
                        // }

                        if (token.type === 'eof') {
                            throw invalidEOF()
                        }

                        switch (token.value) {
                            case ',':
                                parseState = 'beforeArrayValue';
                                return

                            case ']':
                                pop();
                        }

                        // This code is unreachable since it's handled by the lexState.
                        // throw invalidToken()
                    },

                    end: function end() {
                        // This code is unreachable since it's handled by the lexState.
                        // if (token.type !== 'eof') {
                        //     throw invalidToken()
                        // }
                    },
                };

                function push() {
                    var value;

                    switch (token.type) {
                        case 'punctuator':
                            switch (token.value) {
                                case '{':
                                    value = {};
                                    break

                                case '[':
                                    value = [];
                                    break
                            }

                            break

                        case 'null':
                        case 'boolean':
                        case 'numeric':
                        case 'string':
                            value = token.value;
                            break

                        // This code is unreachable.
                        // default:
                        //     throw invalidToken()
                    }

                    if (root === undefined) {
                        root = value;
                    } else {
                        var parent = stack[stack.length - 1];
                        if (Array.isArray(parent)) {
                            parent.push(value);
                        } else {
                            parent[key] = value;
                        }
                    }

                    if (value !== null && typeof value === 'object') {
                        stack.push(value);

                        if (Array.isArray(value)) {
                            parseState = 'beforeArrayValue';
                        } else {
                            parseState = 'beforePropertyName';
                        }
                    } else {
                        var current = stack[stack.length - 1];
                        if (current == null) {
                            parseState = 'end';
                        } else if (Array.isArray(current)) {
                            parseState = 'afterArrayValue';
                        } else {
                            parseState = 'afterPropertyValue';
                        }
                    }
                }

                function pop() {
                    stack.pop();

                    var current = stack[stack.length - 1];
                    if (current == null) {
                        parseState = 'end';
                    } else if (Array.isArray(current)) {
                        parseState = 'afterArrayValue';
                    } else {
                        parseState = 'afterPropertyValue';
                    }
                }

                // This code is unreachable.
                // function invalidParseState () {
                //     return new Error(`JSON5: invalid parse state '${parseState}'`)
                // }

                // This code is unreachable.
                // function invalidLexState (state) {
                //     return new Error(`JSON5: invalid lex state '${state}'`)
                // }

                function invalidChar(c) {
                    if (c === undefined) {
                        return syntaxError(("JSON5: invalid end of input at " + line + ":" + column))
                    }

                    return syntaxError(("JSON5: invalid character '" + (formatChar(c)) + "' at " + line + ":" + column))
                }

                function invalidEOF() {
                    return syntaxError(("JSON5: invalid end of input at " + line + ":" + column))
                }

                // This code is unreachable.
                // function invalidToken () {
                //     if (token.type === 'eof') {
                //         return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
                //     }

                //     const c = String.fromCodePoint(token.value.codePointAt(0))
                //     return syntaxError(`JSON5: invalid character '${formatChar(c)}' at ${line}:${column}`)
                // }

                function invalidIdentifier() {
                    column -= 5;
                    return syntaxError(("JSON5: invalid identifier character at " + line + ":" + column))
                }

                function separatorChar(c) {
                    console.warn(("JSON5: '" + (formatChar(c)) + "' in strings is not valid ECMAScript; consider escaping"));
                }

                function formatChar(c) {
                    var replacements = {
                        "'": "\\'",
                        '"': '\\"',
                        '\\': '\\\\',
                        '\b': '\\b',
                        '\f': '\\f',
                        '\n': '\\n',
                        '\r': '\\r',
                        '\t': '\\t',
                        '\v': '\\v',
                        '\0': '\\0',
                        '\u2028': '\\u2028',
                        '\u2029': '\\u2029',
                    };

                    if (replacements[c]) {
                        return replacements[c]
                    }

                    if (c < ' ') {
                        var hexString = c.charCodeAt(0).toString(16);
                        return '\\x' + ('00' + hexString).substring(hexString.length)
                    }

                    return c
                }

                function syntaxError(message) {
                    var err = new SyntaxError(message);
                    err.lineNumber = line;
                    err.columnNumber = column;
                    return err
                }

                var stringify = function stringify(value, replacer, space) {
                    var stack = [];
                    var indent = '';
                    var propertyList;
                    var replacerFunc;
                    var gap = '';
                    var quote;

                    if (
                        replacer != null &&
                        typeof replacer === 'object' &&
                        !Array.isArray(replacer)
                    ) {
                        space = replacer.space;
                        quote = replacer.quote;
                        replacer = replacer.replacer;
                    }

                    if (typeof replacer === 'function') {
                        replacerFunc = replacer;
                    } else if (Array.isArray(replacer)) {
                        propertyList = [];
                        for (var i = 0, list = replacer; i < list.length; i += 1) {
                            var v = list[i];

                            var item = (void 0);

                            if (typeof v === 'string') {
                                item = v;
                            } else if (
                                typeof v === 'number' ||
                                v instanceof String ||
                                v instanceof Number
                            ) {
                                item = String(v);
                            }

                            if (item !== undefined && propertyList.indexOf(item) < 0) {
                                propertyList.push(item);
                            }
                        }
                    }

                    if (space instanceof Number) {
                        space = Number(space);
                    } else if (space instanceof String) {
                        space = String(space);
                    }

                    if (typeof space === 'number') {
                        if (space > 0) {
                            space = Math.min(10, Math.floor(space));
                            gap = '          '.substr(0, space);
                        }
                    } else if (typeof space === 'string') {
                        gap = space.substr(0, 10);
                    }

                    return serializeProperty('', { '': value })

                    function serializeProperty(key, holder) {
                        var value = holder[key];
                        if (value != null) {
                            if (typeof value.toJSON5 === 'function') {
                                value = value.toJSON5(key);
                            } else if (typeof value.toJSON === 'function') {
                                value = value.toJSON(key);
                            }
                        }

                        if (replacerFunc) {
                            value = replacerFunc.call(holder, key, value);
                        }

                        if (value instanceof Number) {
                            value = Number(value);
                        } else if (value instanceof String) {
                            value = String(value);
                        } else if (value instanceof Boolean) {
                            value = value.valueOf();
                        }

                        switch (value) {
                            case null: return 'null'
                            case true: return 'true'
                            case false: return 'false'
                        }

                        if (typeof value === 'string') {
                            return quoteString(value, false)
                        }

                        if (typeof value === 'number') {
                            return String(value)
                        }

                        if (typeof value === 'object') {
                            return Array.isArray(value) ? serializeArray(value) : serializeObject(value)
                        }

                        return undefined
                    }

                    function quoteString(value) {
                        var quotes = {
                            "'": 0.1,
                            '"': 0.2,
                        };

                        var replacements = {
                            "'": "\\'",
                            '"': '\\"',
                            '\\': '\\\\',
                            '\b': '\\b',
                            '\f': '\\f',
                            '\n': '\\n',
                            '\r': '\\r',
                            '\t': '\\t',
                            '\v': '\\v',
                            '\0': '\\0',
                            '\u2028': '\\u2028',
                            '\u2029': '\\u2029',
                        };

                        var product = '';

                        for (var i = 0; i < value.length; i++) {
                            var c = value[i];
                            switch (c) {
                                case "'":
                                case '"':
                                    quotes[c]++;
                                    product += c;
                                    continue

                                case '\0':
                                    if (util.isDigit(value[i + 1])) {
                                        product += '\\x00';
                                        continue
                                    }
                            }

                            if (replacements[c]) {
                                product += replacements[c];
                                continue
                            }

                            if (c < ' ') {
                                var hexString = c.charCodeAt(0).toString(16);
                                product += '\\x' + ('00' + hexString).substring(hexString.length);
                                continue
                            }

                            product += c;
                        }

                        var quoteChar = quote || Object.keys(quotes).reduce(function (a, b) { return (quotes[a] < quotes[b]) ? a : b; });

                        product = product.replace(new RegExp(quoteChar, 'g'), replacements[quoteChar]);

                        return quoteChar + product + quoteChar
                    }

                    function serializeObject(value) {
                        if (stack.indexOf(value) >= 0) {
                            throw TypeError('Converting circular structure to JSON5')
                        }

                        stack.push(value);

                        var stepback = indent;
                        indent = indent + gap;

                        var keys = propertyList || Object.keys(value);
                        var partial = [];
                        for (var i = 0, list = keys; i < list.length; i += 1) {
                            var key = list[i];

                            var propertyString = serializeProperty(key, value);
                            if (propertyString !== undefined) {
                                var member = serializeKey(key) + ':';
                                if (gap !== '') {
                                    member += ' ';
                                }
                                member += propertyString;
                                partial.push(member);
                            }
                        }

                        var final;
                        if (partial.length === 0) {
                            final = '{}';
                        } else {
                            var properties;
                            if (gap === '') {
                                properties = partial.join(',');
                                final = '{' + properties + '}';
                            } else {
                                var separator = ',\n' + indent;
                                properties = partial.join(separator);
                                final = '{\n' + indent + properties + ',\n' + stepback + '}';
                            }
                        }

                        stack.pop();
                        indent = stepback;
                        return final
                    }

                    function serializeKey(key) {
                        if (key.length === 0) {
                            return quoteString(key, true)
                        }

                        var firstChar = String.fromCodePoint(key.codePointAt(0));
                        if (!util.isIdStartChar(firstChar)) {
                            return quoteString(key, true)
                        }

                        for (var i = firstChar.length; i < key.length; i++) {
                            if (!util.isIdContinueChar(String.fromCodePoint(key.codePointAt(i)))) {
                                return quoteString(key, true)
                            }
                        }

                        return key
                    }

                    function serializeArray(value) {
                        if (stack.indexOf(value) >= 0) {
                            throw TypeError('Converting circular structure to JSON5')
                        }

                        stack.push(value);

                        var stepback = indent;
                        indent = indent + gap;

                        var partial = [];
                        for (var i = 0; i < value.length; i++) {
                            var propertyString = serializeProperty(String(i), value);
                            partial.push((propertyString !== undefined) ? propertyString : 'null');
                        }

                        var final;
                        if (partial.length === 0) {
                            final = '[]';
                        } else {
                            if (gap === '') {
                                var properties = partial.join(',');
                                final = '[' + properties + ']';
                            } else {
                                var separator = ',\n' + indent;
                                var properties$1 = partial.join(separator);
                                final = '[\n' + indent + properties$1 + ',\n' + stepback + ']';
                            }
                        }

                        stack.pop();
                        indent = stepback;
                        return final
                    }
                };

                var JSON5 = {
                    parse: parse,
                    stringify: stringify,
                };

                var lib = JSON5;

                var es5 = lib;

                return es5;

            })));

        }, {}], 102: [function (require, module, exports) {
            (function (global) {
                (function () {
                    /**
                     * @license
                     * Lodash <https://lodash.com/>
                     * Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
                     * Released under MIT license <https://lodash.com/license>
                     * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
                     * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
                     */
                    ; (function () {

                        /** Used as a safe reference for `undefined` in pre-ES5 environments. */
                        var undefined;

                        /** Used as the semantic version number. */
                        var VERSION = '4.17.21';

                        /** Used as the size to enable large array optimizations. */
                        var LARGE_ARRAY_SIZE = 200;

                        /** Error message constants. */
                        var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.',
                            FUNC_ERROR_TEXT = 'Expected a function',
                            INVALID_TEMPL_VAR_ERROR_TEXT = 'Invalid `variable` option passed into `_.template`';

                        /** Used to stand-in for `undefined` hash values. */
                        var HASH_UNDEFINED = '__lodash_hash_undefined__';

                        /** Used as the maximum memoize cache size. */
                        var MAX_MEMOIZE_SIZE = 500;

                        /** Used as the internal argument placeholder. */
                        var PLACEHOLDER = '__lodash_placeholder__';

                        /** Used to compose bitmasks for cloning. */
                        var CLONE_DEEP_FLAG = 1,
                            CLONE_FLAT_FLAG = 2,
                            CLONE_SYMBOLS_FLAG = 4;

                        /** Used to compose bitmasks for value comparisons. */
                        var COMPARE_PARTIAL_FLAG = 1,
                            COMPARE_UNORDERED_FLAG = 2;

                        /** Used to compose bitmasks for function metadata. */
                        var WRAP_BIND_FLAG = 1,
                            WRAP_BIND_KEY_FLAG = 2,
                            WRAP_CURRY_BOUND_FLAG = 4,
                            WRAP_CURRY_FLAG = 8,
                            WRAP_CURRY_RIGHT_FLAG = 16,
                            WRAP_PARTIAL_FLAG = 32,
                            WRAP_PARTIAL_RIGHT_FLAG = 64,
                            WRAP_ARY_FLAG = 128,
                            WRAP_REARG_FLAG = 256,
                            WRAP_FLIP_FLAG = 512;

                        /** Used as default options for `_.truncate`. */
                        var DEFAULT_TRUNC_LENGTH = 30,
                            DEFAULT_TRUNC_OMISSION = '...';

                        /** Used to detect hot functions by number of calls within a span of milliseconds. */
                        var HOT_COUNT = 800,
                            HOT_SPAN = 16;

                        /** Used to indicate the type of lazy iteratees. */
                        var LAZY_FILTER_FLAG = 1,
                            LAZY_MAP_FLAG = 2,
                            LAZY_WHILE_FLAG = 3;

                        /** Used as references for various `Number` constants. */
                        var INFINITY = 1 / 0,
                            MAX_SAFE_INTEGER = 9007199254740991,
                            MAX_INTEGER = 1.7976931348623157e+308,
                            NAN = 0 / 0;

                        /** Used as references for the maximum length and index of an array. */
                        var MAX_ARRAY_LENGTH = 4294967295,
                            MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
                            HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;

                        /** Used to associate wrap methods with their bit flags. */
                        var wrapFlags = [
                            ['ary', WRAP_ARY_FLAG],
                            ['bind', WRAP_BIND_FLAG],
                            ['bindKey', WRAP_BIND_KEY_FLAG],
                            ['curry', WRAP_CURRY_FLAG],
                            ['curryRight', WRAP_CURRY_RIGHT_FLAG],
                            ['flip', WRAP_FLIP_FLAG],
                            ['partial', WRAP_PARTIAL_FLAG],
                            ['partialRight', WRAP_PARTIAL_RIGHT_FLAG],
                            ['rearg', WRAP_REARG_FLAG]
                        ];

                        /** `Object#toString` result references. */
                        var argsTag = '[object Arguments]',
                            arrayTag = '[object Array]',
                            asyncTag = '[object AsyncFunction]',
                            boolTag = '[object Boolean]',
                            dateTag = '[object Date]',
                            domExcTag = '[object DOMException]',
                            errorTag = '[object Error]',
                            funcTag = '[object Function]',
                            genTag = '[object GeneratorFunction]',
                            mapTag = '[object Map]',
                            numberTag = '[object Number]',
                            nullTag = '[object Null]',
                            objectTag = '[object Object]',
                            promiseTag = '[object Promise]',
                            proxyTag = '[object Proxy]',
                            regexpTag = '[object RegExp]',
                            setTag = '[object Set]',
                            stringTag = '[object String]',
                            symbolTag = '[object Symbol]',
                            undefinedTag = '[object Undefined]',
                            weakMapTag = '[object WeakMap]',
                            weakSetTag = '[object WeakSet]';

                        var arrayBufferTag = '[object ArrayBuffer]',
                            dataViewTag = '[object DataView]',
                            float32Tag = '[object Float32Array]',
                            float64Tag = '[object Float64Array]',
                            int8Tag = '[object Int8Array]',
                            int16Tag = '[object Int16Array]',
                            int32Tag = '[object Int32Array]',
                            uint8Tag = '[object Uint8Array]',
                            uint8ClampedTag = '[object Uint8ClampedArray]',
                            uint16Tag = '[object Uint16Array]',
                            uint32Tag = '[object Uint32Array]';

                        /** Used to match empty string literals in compiled template source. */
                        var reEmptyStringLeading = /\b__p \+= '';/g,
                            reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
                            reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;

                        /** Used to match HTML entities and HTML characters. */
                        var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g,
                            reUnescapedHtml = /[&<>"']/g,
                            reHasEscapedHtml = RegExp(reEscapedHtml.source),
                            reHasUnescapedHtml = RegExp(reUnescapedHtml.source);

                        /** Used to match template delimiters. */
                        var reEscape = /<%-([\s\S]+?)%>/g,
                            reEvaluate = /<%([\s\S]+?)%>/g,
                            reInterpolate = /<%=([\s\S]+?)%>/g;

                        /** Used to match property names within property paths. */
                        var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
                            reIsPlainProp = /^\w*$/,
                            rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;

                        /**
                         * Used to match `RegExp`
                         * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
                         */
                        var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
                            reHasRegExpChar = RegExp(reRegExpChar.source);

                        /** Used to match leading whitespace. */
                        var reTrimStart = /^\s+/;

                        /** Used to match a single whitespace character. */
                        var reWhitespace = /\s/;

                        /** Used to match wrap detail comments. */
                        var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,
                            reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/,
                            reSplitDetails = /,? & /;

                        /** Used to match words composed of alphanumeric characters. */
                        var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;

                        /**
                         * Used to validate the `validate` option in `_.template` variable.
                         *
                         * Forbids characters which could potentially change the meaning of the function argument definition:
                         * - "()," (modification of function parameters)
                         * - "=" (default value)
                         * - "[]{}" (destructuring of function parameters)
                         * - "/" (beginning of a comment)
                         * - whitespace
                         */
                        var reForbiddenIdentifierChars = /[()=,{}\[\]\/\s]/;

                        /** Used to match backslashes in property paths. */
                        var reEscapeChar = /\\(\\)?/g;

                        /**
                         * Used to match
                         * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components).
                         */
                        var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;

                        /** Used to match `RegExp` flags from their coerced string values. */
                        var reFlags = /\w*$/;

                        /** Used to detect bad signed hexadecimal string values. */
                        var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;

                        /** Used to detect binary string values. */
                        var reIsBinary = /^0b[01]+$/i;

                        /** Used to detect host constructors (Safari). */
                        var reIsHostCtor = /^\[object .+?Constructor\]$/;

                        /** Used to detect octal string values. */
                        var reIsOctal = /^0o[0-7]+$/i;

                        /** Used to detect unsigned integer values. */
                        var reIsUint = /^(?:0|[1-9]\d*)$/;

                        /** Used to match Latin Unicode letters (excluding mathematical operators). */
                        var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;

                        /** Used to ensure capturing order of template delimiters. */
                        var reNoMatch = /($^)/;

                        /** Used to match unescaped characters in compiled string literals. */
                        var reUnescapedString = /['\n\r\u2028\u2029\\]/g;

                        /** Used to compose unicode character classes. */
                        var rsAstralRange = '\\ud800-\\udfff',
                            rsComboMarksRange = '\\u0300-\\u036f',
                            reComboHalfMarksRange = '\\ufe20-\\ufe2f',
                            rsComboSymbolsRange = '\\u20d0-\\u20ff',
                            rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,
                            rsDingbatRange = '\\u2700-\\u27bf',
                            rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
                            rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
                            rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
                            rsPunctuationRange = '\\u2000-\\u206f',
                            rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',
                            rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
                            rsVarRange = '\\ufe0e\\ufe0f',
                            rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;

                        /** Used to compose unicode capture groups. */
                        var rsApos = "['\u2019]",
                            rsAstral = '[' + rsAstralRange + ']',
                            rsBreak = '[' + rsBreakRange + ']',
                            rsCombo = '[' + rsComboRange + ']',
                            rsDigits = '\\d+',
                            rsDingbat = '[' + rsDingbatRange + ']',
                            rsLower = '[' + rsLowerRange + ']',
                            rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',
                            rsFitz = '\\ud83c[\\udffb-\\udfff]',
                            rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
                            rsNonAstral = '[^' + rsAstralRange + ']',
                            rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
                            rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
                            rsUpper = '[' + rsUpperRange + ']',
                            rsZWJ = '\\u200d';

                        /** Used to compose unicode regexes. */
                        var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')',
                            rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')',
                            rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
                            rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
                            reOptMod = rsModifier + '?',
                            rsOptVar = '[' + rsVarRange + ']?',
                            rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
                            rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])',
                            rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])',
                            rsSeq = rsOptVar + reOptMod + rsOptJoin,
                            rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
                            rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';

                        /** Used to match apostrophes. */
                        var reApos = RegExp(rsApos, 'g');

                        /**
                         * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
                         * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
                         */
                        var reComboMark = RegExp(rsCombo, 'g');

                        /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
                        var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');

                        /** Used to match complex or compound words. */
                        var reUnicodeWord = RegExp([
                            rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',
                            rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')',
                            rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower,
                            rsUpper + '+' + rsOptContrUpper,
                            rsOrdUpper,
                            rsOrdLower,
                            rsDigits,
                            rsEmoji
                        ].join('|'), 'g');

                        /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
                        var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');

                        /** Used to detect strings that need a more robust regexp to match words. */
                        var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;

                        /** Used to assign default `context` object properties. */
                        var contextProps = [
                            'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array',
                            'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object',
                            'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array',
                            'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
                            '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout'
                        ];

                        /** Used to make template sourceURLs easier to identify. */
                        var templateCounter = -1;

                        /** Used to identify `toStringTag` values of typed arrays. */
                        var typedArrayTags = {};
                        typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
                            typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
                            typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
                            typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
                            typedArrayTags[uint32Tag] = true;
                        typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
                            typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
                            typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
                            typedArrayTags[errorTag] = typedArrayTags[funcTag] =
                            typedArrayTags[mapTag] = typedArrayTags[numberTag] =
                            typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
                            typedArrayTags[setTag] = typedArrayTags[stringTag] =
                            typedArrayTags[weakMapTag] = false;

                        /** Used to identify `toStringTag` values supported by `_.clone`. */
                        var cloneableTags = {};
                        cloneableTags[argsTag] = cloneableTags[arrayTag] =
                            cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
                            cloneableTags[boolTag] = cloneableTags[dateTag] =
                            cloneableTags[float32Tag] = cloneableTags[float64Tag] =
                            cloneableTags[int8Tag] = cloneableTags[int16Tag] =
                            cloneableTags[int32Tag] = cloneableTags[mapTag] =
                            cloneableTags[numberTag] = cloneableTags[objectTag] =
                            cloneableTags[regexpTag] = cloneableTags[setTag] =
                            cloneableTags[stringTag] = cloneableTags[symbolTag] =
                            cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
                            cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
                        cloneableTags[errorTag] = cloneableTags[funcTag] =
                            cloneableTags[weakMapTag] = false;

                        /** Used to map Latin Unicode letters to basic Latin letters. */
                        var deburredLetters = {
                            // Latin-1 Supplement block.
                            '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
                            '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
                            '\xc7': 'C', '\xe7': 'c',
                            '\xd0': 'D', '\xf0': 'd',
                            '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
                            '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
                            '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
                            '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
                            '\xd1': 'N', '\xf1': 'n',
                            '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
                            '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
                            '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
                            '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
                            '\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
                            '\xc6': 'Ae', '\xe6': 'ae',
                            '\xde': 'Th', '\xfe': 'th',
                            '\xdf': 'ss',
                            // Latin Extended-A block.
                            '\u0100': 'A', '\u0102': 'A', '\u0104': 'A',
                            '\u0101': 'a', '\u0103': 'a', '\u0105': 'a',
                            '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C',
                            '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c',
                            '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd',
                            '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E',
                            '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e',
                            '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G',
                            '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g',
                            '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
                            '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I',
                            '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i',
                            '\u0134': 'J', '\u0135': 'j',
                            '\u0136': 'K', '\u0137': 'k', '\u0138': 'k',
                            '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L',
                            '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l',
                            '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N',
                            '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n',
                            '\u014c': 'O', '\u014e': 'O', '\u0150': 'O',
                            '\u014d': 'o', '\u014f': 'o', '\u0151': 'o',
                            '\u0154': 'R', '\u0156': 'R', '\u0158': 'R',
                            '\u0155': 'r', '\u0157': 'r', '\u0159': 'r',
                            '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S',
                            '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's',
                            '\u0162': 'T', '\u0164': 'T', '\u0166': 'T',
                            '\u0163': 't', '\u0165': 't', '\u0167': 't',
                            '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U',
                            '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u',
                            '\u0174': 'W', '\u0175': 'w',
                            '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y',
                            '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z',
                            '\u017a': 'z', '\u017c': 'z', '\u017e': 'z',
                            '\u0132': 'IJ', '\u0133': 'ij',
                            '\u0152': 'Oe', '\u0153': 'oe',
                            '\u0149': "'n", '\u017f': 's'
                        };

                        /** Used to map characters to HTML entities. */
                        var htmlEscapes = {
                            '&': '&amp;',
                            '<': '&lt;',
                            '>': '&gt;',
                            '"': '&quot;',
                            "'": '&#39;'
                        };

                        /** Used to map HTML entities to characters. */
                        var htmlUnescapes = {
                            '&amp;': '&',
                            '&lt;': '<',
                            '&gt;': '>',
                            '&quot;': '"',
                            '&#39;': "'"
                        };

                        /** Used to escape characters for inclusion in compiled string literals. */
                        var stringEscapes = {
                            '\\': '\\',
                            "'": "'",
                            '\n': 'n',
                            '\r': 'r',
                            '\u2028': 'u2028',
                            '\u2029': 'u2029'
                        };

                        /** Built-in method references without a dependency on `root`. */
                        var freeParseFloat = parseFloat,
                            freeParseInt = parseInt;

                        /** Detect free variable `global` from Node.js. */
                        var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;

                        /** Detect free variable `self`. */
                        var freeSelf = typeof self == 'object' && self && self.Object === Object && self;

                        /** Used as a reference to the global object. */
                        var root = freeGlobal || freeSelf || Function('return this')();

                        /** Detect free variable `exports`. */
                        var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;

                        /** Detect free variable `module`. */
                        var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;

                        /** Detect the popular CommonJS extension `module.exports`. */
                        var moduleExports = freeModule && freeModule.exports === freeExports;

                        /** Detect free variable `process` from Node.js. */
                        var freeProcess = moduleExports && freeGlobal.process;

                        /** Used to access faster Node.js helpers. */
                        var nodeUtil = (function () {
                            try {
                                // Use `util.types` for Node.js 10+.
                                var types = freeModule && freeModule.require && freeModule.require('util').types;

                                if (types) {
                                    return types;
                                }

                                // Legacy `process.binding('util')` for Node.js < 10.
                                return freeProcess && freeProcess.binding && freeProcess.binding('util');
                            } catch (e) { }
                        }());

                        /* Node.js helper references. */
                        var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer,
                            nodeIsDate = nodeUtil && nodeUtil.isDate,
                            nodeIsMap = nodeUtil && nodeUtil.isMap,
                            nodeIsRegExp = nodeUtil && nodeUtil.isRegExp,
                            nodeIsSet = nodeUtil && nodeUtil.isSet,
                            nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;

                        /*--------------------------------------------------------------------------*/

                        /**
                         * A faster alternative to `Function#apply`, this function invokes `func`
                         * with the `this` binding of `thisArg` and the arguments of `args`.
                         *
                         * @private
                         * @param {Function} func The function to invoke.
                         * @param {*} thisArg The `this` binding of `func`.
                         * @param {Array} args The arguments to invoke `func` with.
                         * @returns {*} Returns the result of `func`.
                         */
                        function apply(func, thisArg, args) {
                            switch (args.length) {
                                case 0: return func.call(thisArg);
                                case 1: return func.call(thisArg, args[0]);
                                case 2: return func.call(thisArg, args[0], args[1]);
                                case 3: return func.call(thisArg, args[0], args[1], args[2]);
                            }
                            return func.apply(thisArg, args);
                        }

                        /**
                         * A specialized version of `baseAggregator` for arrays.
                         *
                         * @private
                         * @param {Array} [array] The array to iterate over.
                         * @param {Function} setter The function to set `accumulator` values.
                         * @param {Function} iteratee The iteratee to transform keys.
                         * @param {Object} accumulator The initial aggregated object.
                         * @returns {Function} Returns `accumulator`.
                         */
                        function arrayAggregator(array, setter, iteratee, accumulator) {
                            var index = -1,
                                length = array == null ? 0 : array.length;

                            while (++index < length) {
                                var value = array[index];
                                setter(accumulator, value, iteratee(value), array);
                            }
                            return accumulator;
                        }

                        /**
                         * A specialized version of `_.forEach` for arrays without support for
                         * iteratee shorthands.
                         *
                         * @private
                         * @param {Array} [array] The array to iterate over.
                         * @param {Function} iteratee The function invoked per iteration.
                         * @returns {Array} Returns `array`.
                         */
                        function arrayEach(array, iteratee) {
                            var index = -1,
                                length = array == null ? 0 : array.length;

                            while (++index < length) {
                                if (iteratee(array[index], index, array) === false) {
                                    break;
                                }
                            }
                            return array;
                        }

                        /**
                         * A specialized version of `_.forEachRight` for arrays without support for
                         * iteratee shorthands.
                         *
                         * @private
                         * @param {Array} [array] The array to iterate over.
                         * @param {Function} iteratee The function invoked per iteration.
                         * @returns {Array} Returns `array`.
                         */
                        function arrayEachRight(array, iteratee) {
                            var length = array == null ? 0 : array.length;

                            while (length--) {
                                if (iteratee(array[length], length, array) === false) {
                                    break;
                                }
                            }
                            return array;
                        }

                        /**
                         * A specialized version of `_.every` for arrays without support for
                         * iteratee shorthands.
                         *
                         * @private
                         * @param {Array} [array] The array to iterate over.
                         * @param {Function} predicate The function invoked per iteration.
                         * @returns {boolean} Returns `true` if all elements pass the predicate check,
                         *  else `false`.
                         */
                        function arrayEvery(array, predicate) {
                            var index = -1,
                                length = array == null ? 0 : array.length;

                            while (++index < length) {
                                if (!predicate(array[index], index, array)) {
                                    return false;
                                }
                            }
                            return true;
                        }

                        /**
                         * A specialized version of `_.filter` for arrays without support for
                         * iteratee shorthands.
                         *
                         * @private
                         * @param {Array} [array] The array to iterate over.
                         * @param {Function} predicate The function invoked per iteration.
                         * @returns {Array} Returns the new filtered array.
                         */
                        function arrayFilter(array, predicate) {
                            var index = -1,
                                length = array == null ? 0 : array.length,
                                resIndex = 0,
                                result = [];

                            while (++index < length) {
                                var value = array[index];
                                if (predicate(value, index, array)) {
                                    result[resIndex++] = value;
                                }
                            }
                            return result;
                        }

                        /**
                         * A specialized version of `_.includes` for arrays without support for
                         * specifying an index to search from.
                         *
                         * @private
                         * @param {Array} [array] The array to inspect.
                         * @param {*} target The value to search for.
                         * @returns {boolean} Returns `true` if `target` is found, else `false`.
                         */
                        function arrayIncludes(array, value) {
                            var length = array == null ? 0 : array.length;
                            return !!length && baseIndexOf(array, value, 0) > -1;
                        }

                        /**
                         * This function is like `arrayIncludes` except that it accepts a comparator.
                         *
                         * @private
                         * @param {Array} [array] The array to inspect.
                         * @param {*} target The value to search for.
                         * @param {Function} comparator The comparator invoked per element.
                         * @returns {boolean} Returns `true` if `target` is found, else `false`.
                         */
                        function arrayIncludesWith(array, value, comparator) {
                            var index = -1,
                                length = array == null ? 0 : array.length;

                            while (++index < length) {
                                if (comparator(value, array[index])) {
                                    return true;
                                }
                            }
                            return false;
                        }

                        /**
                         * A specialized version of `_.map` for arrays without support for iteratee
                         * shorthands.
                         *
                         * @private
                         * @param {Array} [array] The array to iterate over.
                         * @param {Function} iteratee The function invoked per iteration.
                         * @returns {Array} Returns the new mapped array.
                         */
                        function arrayMap(array, iteratee) {
                            var index = -1,
                                length = array == null ? 0 : array.length,
                                result = Array(length);

                            while (++index < length) {
                                result[index] = iteratee(array[index], index, array);
                            }
                            return result;
                        }

                        /**
                         * Appends the elements of `values` to `array`.
                         *
                         * @private
                         * @param {Array} array The array to modify.
                         * @param {Array} values The values to append.
                         * @returns {Array} Returns `array`.
                         */
                        function arrayPush(array, values) {
                            var index = -1,
                                length = values.length,
                                offset = array.length;

                            while (++index < length) {
                                array[offset + index] = values[index];
                            }
                            return array;
                        }

                        /**
                         * A specialized version of `_.reduce` for arrays without support for
                         * iteratee shorthands.
                         *
                         * @private
                         * @param {Array} [array] The array to iterate over.
                         * @param {Function} iteratee The function invoked per iteration.
                         * @param {*} [accumulator] The initial value.
                         * @param {boolean} [initAccum] Specify using the first element of `array` as
                         *  the initial value.
                         * @returns {*} Returns the accumulated value.
                         */
                        function arrayReduce(array, iteratee, accumulator, initAccum) {
                            var index = -1,
                                length = array == null ? 0 : array.length;

                            if (initAccum && length) {
                                accumulator = array[++index];
                            }
                            while (++index < length) {
                                accumulator = iteratee(accumulator, array[index], index, array);
                            }
                            return accumulator;
                        }

                        /**
                         * A specialized version of `_.reduceRight` for arrays without support for
                         * iteratee shorthands.
                         *
                         * @private
                         * @param {Array} [array] The array to iterate over.
                         * @param {Function} iteratee The function invoked per iteration.
                         * @param {*} [accumulator] The initial value.
                         * @param {boolean} [initAccum] Specify using the last element of `array` as
                         *  the initial value.
                         * @returns {*} Returns the accumulated value.
                         */
                        function arrayReduceRight(array, iteratee, accumulator, initAccum) {
                            var length = array == null ? 0 : array.length;
                            if (initAccum && length) {
                                accumulator = array[--length];
                            }
                            while (length--) {
                                accumulator = iteratee(accumulator, array[length], length, array);
                            }
                            return accumulator;
                        }

                        /**
                         * A specialized version of `_.some` for arrays without support for iteratee
                         * shorthands.
                         *
                         * @private
                         * @param {Array} [array] The array to iterate over.
                         * @param {Function} predicate The function invoked per iteration.
                         * @returns {boolean} Returns `true` if any element passes the predicate check,
                         *  else `false`.
                         */
                        function arraySome(array, predicate) {
                            var index = -1,
                                length = array == null ? 0 : array.length;

                            while (++index < length) {
                                if (predicate(array[index], index, array)) {
                                    return true;
                                }
                            }
                            return false;
                        }

                        /**
                         * Gets the size of an ASCII `string`.
                         *
                         * @private
                         * @param {string} string The string inspect.
                         * @returns {number} Returns the string size.
                         */
                        var asciiSize = baseProperty('length');

                        /**
                         * Converts an ASCII `string` to an array.
                         *
                         * @private
                         * @param {string} string The string to convert.
                         * @returns {Array} Returns the converted array.
                         */
                        function asciiToArray(string) {
                            return string.split('');
                        }

                        /**
                         * Splits an ASCII `string` into an array of its words.
                         *
                         * @private
                         * @param {string} The string to inspect.
                         * @returns {Array} Returns the words of `string`.
                         */
                        function asciiWords(string) {
                            return string.match(reAsciiWord) || [];
                        }

                        /**
                         * The base implementation of methods like `_.findKey` and `_.findLastKey`,
                         * without support for iteratee shorthands, which iterates over `collection`
                         * using `eachFunc`.
                         *
                         * @private
                         * @param {Array|Object} collection The collection to inspect.
                         * @param {Function} predicate The function invoked per iteration.
                         * @param {Function} eachFunc The function to iterate over `collection`.
                         * @returns {*} Returns the found element or its key, else `undefined`.
                         */
                        function baseFindKey(collection, predicate, eachFunc) {
                            var result;
                            eachFunc(collection, function (value, key, collection) {
                                if (predicate(value, key, collection)) {
                                    result = key;
                                    return false;
                                }
                            });
                            return result;
                        }

                        /**
                         * The base implementation of `_.findIndex` and `_.findLastIndex` without
                         * support for iteratee shorthands.
                         *
                         * @private
                         * @param {Array} array The array to inspect.
                         * @param {Function} predicate The function invoked per iteration.
                         * @param {number} fromIndex The index to search from.
                         * @param {boolean} [fromRight] Specify iterating from right to left.
                         * @returns {number} Returns the index of the matched value, else `-1`.
                         */
                        function baseFindIndex(array, predicate, fromIndex, fromRight) {
                            var length = array.length,
                                index = fromIndex + (fromRight ? 1 : -1);

                            while ((fromRight ? index-- : ++index < length)) {
                                if (predicate(array[index], index, array)) {
                                    return index;
                                }
                            }
                            return -1;
                        }

                        /**
                         * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
                         *
                         * @private
                         * @param {Array} array The array to inspect.
                         * @param {*} value The value to search for.
                         * @param {number} fromIndex The index to search from.
                         * @returns {number} Returns the index of the matched value, else `-1`.
                         */
                        function baseIndexOf(array, value, fromIndex) {
                            return value === value
                                ? strictIndexOf(array, value, fromIndex)
                                : baseFindIndex(array, baseIsNaN, fromIndex);
                        }

                        /**
                         * This function is like `baseIndexOf` except that it accepts a comparator.
                         *
                         * @private
                         * @param {Array} array The array to inspect.
                         * @param {*} value The value to search for.
                         * @param {number} fromIndex The index to search from.
                         * @param {Function} comparator The comparator invoked per element.
                         * @returns {number} Returns the index of the matched value, else `-1`.
                         */
                        function baseIndexOfWith(array, value, fromIndex, comparator) {
                            var index = fromIndex - 1,
                                length = array.length;

                            while (++index < length) {
                                if (comparator(array[index], value)) {
                                    return index;
                                }
                            }
                            return -1;
                        }

                        /**
                         * The base implementation of `_.isNaN` without support for number objects.
                         *
                         * @private
                         * @param {*} value The value to check.
                         * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
                         */
                        function baseIsNaN(value) {
                            return value !== value;
                        }

                        /**
                         * The base implementation of `_.mean` and `_.meanBy` without support for
                         * iteratee shorthands.
                         *
                         * @private
                         * @param {Array} array The array to iterate over.
                         * @param {Function} iteratee The function invoked per iteration.
                         * @returns {number} Returns the mean.
                         */
                        function baseMean(array, iteratee) {
                            var length = array == null ? 0 : array.length;
                            return length ? (baseSum(array, iteratee) / length) : NAN;
                        }

                        /**
                         * The base implementation of `_.property` without support for deep paths.
                         *
                         * @private
                         * @param {string} key The key of the property to get.
                         * @returns {Function} Returns the new accessor function.
                         */
                        function baseProperty(key) {
                            return function (object) {
                                return object == null ? undefined : object[key];
                            };
                        }

                        /**
                         * The base implementation of `_.propertyOf` without support for deep paths.
                         *
                         * @private
                         * @param {Object} object The object to query.
                         * @returns {Function} Returns the new accessor function.
                         */
                        function basePropertyOf(object) {
                            return function (key) {
                                return object == null ? undefined : object[key];
                            };
                        }

                        /**
                         * The base implementation of `_.reduce` and `_.reduceRight`, without support
                         * for iteratee shorthands, which iterates over `collection` using `eachFunc`.
                         *
                         * @private
                         * @param {Array|Object} collection The collection to iterate over.
                         * @param {Function} iteratee The function invoked per iteration.
                         * @param {*} accumulator The initial value.
                         * @param {boolean} initAccum Specify using the first or last element of
                         *  `collection` as the initial value.
                         * @param {Function} eachFunc The function to iterate over `collection`.
                         * @returns {*} Returns the accumulated value.
                         */
                        function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
                            eachFunc(collection, function (value, index, collection) {
                                accumulator = initAccum
                                    ? (initAccum = false, value)
                                    : iteratee(accumulator, value, index, collection);
                            });
                            return accumulator;
                        }

                        /**
                         * The base implementation of `_.sortBy` which uses `comparer` to define the
                         * sort order of `array` and replaces criteria objects with their corresponding
                         * values.
                         *
                         * @private
                         * @param {Array} array The array to sort.
                         * @param {Function} comparer The function to define sort order.
                         * @returns {Array} Returns `array`.
                         */
                        function baseSortBy(array, comparer) {
                            var length = array.length;

                            array.sort(comparer);
                            while (length--) {
                                array[length] = array[length].value;
                            }
                            return array;
                        }

                        /**
                         * The base implementation of `_.sum` and `_.sumBy` without support for
                         * iteratee shorthands.
                         *
                         * @private
                         * @param {Array} array The array to iterate over.
                         * @param {Function} iteratee The function invoked per iteration.
                         * @returns {number} Returns the sum.
                         */
                        function baseSum(array, iteratee) {
                            var result,
                                index = -1,
                                length = array.length;

                            while (++index < length) {
                                var current = iteratee(array[index]);
                                if (current !== undefined) {
                                    result = result === undefined ? current : (result + current);
                                }
                            }
                            return result;
                        }

                        /**
                         * The base implementation of `_.times` without support for iteratee shorthands
                         * or max array length checks.
                         *
                         * @private
                         * @param {number} n The number of times to invoke `iteratee`.
                         * @param {Function} iteratee The function invoked per iteration.
                         * @returns {Array} Returns the array of results.
                         */
                        function baseTimes(n, iteratee) {
                            var index = -1,
                                result = Array(n);

                            while (++index < n) {
                                result[index] = iteratee(index);
                            }
                            return result;
                        }

                        /**
                         * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
                         * of key-value pairs for `object` corresponding to the property names of `props`.
                         *
                         * @private
                         * @param {Object} object The object to query.
                         * @param {Array} props The property names to get values for.
                         * @returns {Object} Returns the key-value pairs.
                         */
                        function baseToPairs(object, props) {
                            return arrayMap(props, function (key) {
                                return [key, object[key]];
                            });
                        }

                        /**
                         * The base implementation of `_.trim`.
                         *
                         * @private
                         * @param {string} string The string to trim.
                         * @returns {string} Returns the trimmed string.
                         */
                        function baseTrim(string) {
                            return string
                                ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')
                                : string;
                        }

                        /**
                         * The base implementation of `_.unary` without support for storing metadata.
                         *
                         * @private
                         * @param {Function} func The function to cap arguments for.
                         * @returns {Function} Returns the new capped function.
                         */
                        function baseUnary(func) {
                            return function (value) {
                                return func(value);
                            };
                        }

                        /**
                         * The base implementation of `_.values` and `_.valuesIn` which creates an
                         * array of `object` property values corresponding to the property names
                         * of `props`.
                         *
                         * @private
                         * @param {Object} object The object to query.
                         * @param {Array} props The property names to get values for.
                         * @returns {Object} Returns the array of property values.
                         */
                        function baseValues(object, props) {
                            return arrayMap(props, function (key) {
                                return object[key];
                            });
                        }

                        /**
                         * Checks if a `cache` value for `key` exists.
                         *
                         * @private
                         * @param {Object} cache The cache to query.
                         * @param {string} key The key of the entry to check.
                         * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
                         */
                        function cacheHas(cache, key) {
                            return cache.has(key);
                        }

                        /**
                         * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
                         * that is not found in the character symbols.
                         *
                         * @private
                         * @param {Array} strSymbols The string symbols to inspect.
                         * @param {Array} chrSymbols The character symbols to find.
                         * @returns {number} Returns the index of the first unmatched string symbol.
                         */
                        function charsStartIndex(strSymbols, chrSymbols) {
                            var index = -1,
                                length = strSymbols.length;

                            while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) { }
                            return index;
                        }

                        /**
                         * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
                         * that is not found in the character symbols.
                         *
                         * @private
                         * @param {Array} strSymbols The string symbols to inspect.
                         * @param {Array} chrSymbols The character symbols to find.
                         * @returns {number} Returns the index of the last unmatched string symbol.
                         */
                        function charsEndIndex(strSymbols, chrSymbols) {
                            var index = strSymbols.length;

                            while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) { }
                            return index;
                        }

                        /**
                         * Gets the number of `placeholder` occurrences in `array`.
                         *
                         * @private
                         * @param {Array} array The array to inspect.
                         * @param {*} placeholder The placeholder to search for.
                         * @returns {number} Returns the placeholder count.
                         */
                        function countHolders(array, placeholder) {
                            var length = array.length,
                                result = 0;

                            while (length--) {
                                if (array[length] === placeholder) {
                                    ++result;
                                }
                            }
                            return result;
                        }

                        /**
                         * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
                         * letters to basic Latin letters.
                         *
                         * @private
                         * @param {string} letter The matched letter to deburr.
                         * @returns {string} Returns the deburred letter.
                         */
                        var deburrLetter = basePropertyOf(deburredLetters);

                        /**
                         * Used by `_.escape` to convert characters to HTML entities.
                         *
                         * @private
                         * @param {string} chr The matched character to escape.
                         * @returns {string} Returns the escaped character.
                         */
                        var escapeHtmlChar = basePropertyOf(htmlEscapes);

                        /**
                         * Used by `_.template` to escape characters for inclusion in compiled string literals.
                         *
                         * @private
                         * @param {string} chr The matched character to escape.
                         * @returns {string} Returns the escaped character.
                         */
                        function escapeStringChar(chr) {
                            return '\\' + stringEscapes[chr];
                        }

                        /**
                         * Gets the value at `key` of `object`.
                         *
                         * @private
                         * @param {Object} [object] The object to query.
                         * @param {string} key The key of the property to get.
                         * @returns {*} Returns the property value.
                         */
                        function getValue(object, key) {
                            return object == null ? undefined : object[key];
                        }

                        /**
                         * Checks if `string` contains Unicode symbols.
                         *
                         * @private
                         * @param {string} string The string to inspect.
                         * @returns {boolean} Returns `true` if a symbol is found, else `false`.
                         */
                        function hasUnicode(string) {
                            return reHasUnicode.test(string);
                        }

                        /**
                         * Checks if `string` contains a word composed of Unicode symbols.
                         *
                         * @private
                         * @param {string} string The string to inspect.
                         * @returns {boolean} Returns `true` if a word is found, else `false`.
                         */
                        function hasUnicodeWord(string) {
                            return reHasUnicodeWord.test(string);
                        }

                        /**
                         * Converts `iterator` to an array.
                         *
                         * @private
                         * @param {Object} iterator The iterator to convert.
                         * @returns {Array} Returns the converted array.
                         */
                        function iteratorToArray(iterator) {
                            var data,
                                result = [];

                            while (!(data = iterator.next()).done) {
                                result.push(data.value);
                            }
                            return result;
                        }

                        /**
                         * Converts `map` to its key-value pairs.
                         *
                         * @private
                         * @param {Object} map The map to convert.
                         * @returns {Array} Returns the key-value pairs.
                         */
                        function mapToArray(map) {
                            var index = -1,
                                result = Array(map.size);

                            map.forEach(function (value, key) {
                                result[++index] = [key, value];
                            });
                            return result;
                        }

                        /**
                         * Creates a unary function that invokes `func` with its argument transformed.
                         *
                         * @private
                         * @param {Function} func The function to wrap.
                         * @param {Function} transform The argument transform.
                         * @returns {Function} Returns the new function.
                         */
                        function overArg(func, transform) {
                            return function (arg) {
                                return func(transform(arg));
                            };
                        }

                        /**
                         * Replaces all `placeholder` elements in `array` with an internal placeholder
                         * and returns an array of their indexes.
                         *
                         * @private
                         * @param {Array} array The array to modify.
                         * @param {*} placeholder The placeholder to replace.
                         * @returns {Array} Returns the new array of placeholder indexes.
                         */
                        function replaceHolders(array, placeholder) {
                            var index = -1,
                                length = array.length,
                                resIndex = 0,
                                result = [];

                            while (++index < length) {
                                var value = array[index];
                                if (value === placeholder || value === PLACEHOLDER) {
                                    array[index] = PLACEHOLDER;
                                    result[resIndex++] = index;
                                }
                            }
                            return result;
                        }

                        /**
                         * Converts `set` to an array of its values.
                         *
                         * @private
                         * @param {Object} set The set to convert.
                         * @returns {Array} Returns the values.
                         */
                        function setToArray(set) {
                            var index = -1,
                                result = Array(set.size);

                            set.forEach(function (value) {
                                result[++index] = value;
                            });
                            return result;
                        }

                        /**
                         * Converts `set` to its value-value pairs.
                         *
                         * @private
                         * @param {Object} set The set to convert.
                         * @returns {Array} Returns the value-value pairs.
                         */
                        function setToPairs(set) {
                            var index = -1,
                                result = Array(set.size);

                            set.forEach(function (value) {
                                result[++index] = [value, value];
                            });
                            return result;
                        }

                        /**
                         * A specialized version of `_.indexOf` which performs strict equality
                         * comparisons of values, i.e. `===`.
                         *
                         * @private
                         * @param {Array} array The array to inspect.
                         * @param {*} value The value to search for.
                         * @param {number} fromIndex The index to search from.
                         * @returns {number} Returns the index of the matched value, else `-1`.
                         */
                        function strictIndexOf(array, value, fromIndex) {
                            var index = fromIndex - 1,
                                length = array.length;

                            while (++index < length) {
                                if (array[index] === value) {
                                    return index;
                                }
                            }
                            return -1;
                        }

                        /**
                         * A specialized version of `_.lastIndexOf` which performs strict equality
                         * comparisons of values, i.e. `===`.
                         *
                         * @private
                         * @param {Array} array The array to inspect.
                         * @param {*} value The value to search for.
                         * @param {number} fromIndex The index to search from.
                         * @returns {number} Returns the index of the matched value, else `-1`.
                         */
                        function strictLastIndexOf(array, value, fromIndex) {
                            var index = fromIndex + 1;
                            while (index--) {
                                if (array[index] === value) {
                                    return index;
                                }
                            }
                            return index;
                        }

                        /**
                         * Gets the number of symbols in `string`.
                         *
                         * @private
                         * @param {string} string The string to inspect.
                         * @returns {number} Returns the string size.
                         */
                        function stringSize(string) {
                            return hasUnicode(string)
                                ? unicodeSize(string)
                                : asciiSize(string);
                        }

                        /**
                         * Converts `string` to an array.
                         *
                         * @private
                         * @param {string} string The string to convert.
                         * @returns {Array} Returns the converted array.
                         */
                        function stringToArray(string) {
                            return hasUnicode(string)
                                ? unicodeToArray(string)
                                : asciiToArray(string);
                        }

                        /**
                         * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
                         * character of `string`.
                         *
                         * @private
                         * @param {string} string The string to inspect.
                         * @returns {number} Returns the index of the last non-whitespace character.
                         */
                        function trimmedEndIndex(string) {
                            var index = string.length;

                            while (index-- && reWhitespace.test(string.charAt(index))) { }
                            return index;
                        }

                        /**
                         * Used by `_.unescape` to convert HTML entities to characters.
                         *
                         * @private
                         * @param {string} chr The matched character to unescape.
                         * @returns {string} Returns the unescaped character.
                         */
                        var unescapeHtmlChar = basePropertyOf(htmlUnescapes);

                        /**
                         * Gets the size of a Unicode `string`.
                         *
                         * @private
                         * @param {string} string The string inspect.
                         * @returns {number} Returns the string size.
                         */
                        function unicodeSize(string) {
                            var result = reUnicode.lastIndex = 0;
                            while (reUnicode.test(string)) {
                                ++result;
                            }
                            return result;
                        }

                        /**
                         * Converts a Unicode `string` to an array.
                         *
                         * @private
                         * @param {string} string The string to convert.
                         * @returns {Array} Returns the converted array.
                         */
                        function unicodeToArray(string) {
                            return string.match(reUnicode) || [];
                        }

                        /**
                         * Splits a Unicode `string` into an array of its words.
                         *
                         * @private
                         * @param {string} The string to inspect.
                         * @returns {Array} Returns the words of `string`.
                         */
                        function unicodeWords(string) {
                            return string.match(reUnicodeWord) || [];
                        }

                        /*--------------------------------------------------------------------------*/

                        /**
                         * Create a new pristine `lodash` function using the `context` object.
                         *
                         * @static
                         * @memberOf _
                         * @since 1.1.0
                         * @category Util
                         * @param {Object} [context=root] The context object.
                         * @returns {Function} Returns a new `lodash` function.
                         * @example
                         *
                         * _.mixin({ 'foo': _.constant('foo') });
                         *
                         * var lodash = _.runInContext();
                         * lodash.mixin({ 'bar': lodash.constant('bar') });
                         *
                         * _.isFunction(_.foo);
                         * // => true
                         * _.isFunction(_.bar);
                         * // => false
                         *
                         * lodash.isFunction(lodash.foo);
                         * // => false
                         * lodash.isFunction(lodash.bar);
                         * // => true
                         *
                         * // Create a suped-up `defer` in Node.js.
                         * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
                         */
                        var runInContext = (function runInContext(context) {
                            context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps));

                            /** Built-in constructor references. */
                            var Array = context.Array,
                                Date = context.Date,
                                Error = context.Error,
                                Function = context.Function,
                                Math = context.Math,
                                Object = context.Object,
                                RegExp = context.RegExp,
                                String = context.String,
                                TypeError = context.TypeError;

                            /** Used for built-in method references. */
                            var arrayProto = Array.prototype,
                                funcProto = Function.prototype,
                                objectProto = Object.prototype;

                            /** Used to detect overreaching core-js shims. */
                            var coreJsData = context['__core-js_shared__'];

                            /** Used to resolve the decompiled source of functions. */
                            var funcToString = funcProto.toString;

                            /** Used to check objects for own properties. */
                            var hasOwnProperty = objectProto.hasOwnProperty;

                            /** Used to generate unique IDs. */
                            var idCounter = 0;

                            /** Used to detect methods masquerading as native. */
                            var maskSrcKey = (function () {
                                var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
                                return uid ? ('Symbol(src)_1.' + uid) : '';
                            }());

                            /**
                             * Used to resolve the
                             * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
                             * of values.
                             */
                            var nativeObjectToString = objectProto.toString;

                            /** Used to infer the `Object` constructor. */
                            var objectCtorString = funcToString.call(Object);

                            /** Used to restore the original `_` reference in `_.noConflict`. */
                            var oldDash = root._;

                            /** Used to detect if a method is native. */
                            var reIsNative = RegExp('^' +
                                funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
                                    .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
                            );

                            /** Built-in value references. */
                            var Buffer = moduleExports ? context.Buffer : undefined,
                                Symbol = context.Symbol,
                                Uint8Array = context.Uint8Array,
                                allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined,
                                getPrototype = overArg(Object.getPrototypeOf, Object),
                                objectCreate = Object.create,
                                propertyIsEnumerable = objectProto.propertyIsEnumerable,
                                splice = arrayProto.splice,
                                spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined,
                                symIterator = Symbol ? Symbol.iterator : undefined,
                                symToStringTag = Symbol ? Symbol.toStringTag : undefined;

                            var defineProperty = (function () {
                                try {
                                    var func = getNative(Object, 'defineProperty');
                                    func({}, '', {});
                                    return func;
                                } catch (e) { }
                            }());

                            /** Mocked built-ins. */
                            var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout,
                                ctxNow = Date && Date.now !== root.Date.now && Date.now,
                                ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout;

                            /* Built-in method references for those with the same name as other `lodash` methods. */
                            var nativeCeil = Math.ceil,
                                nativeFloor = Math.floor,
                                nativeGetSymbols = Object.getOwnPropertySymbols,
                                nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,
                                nativeIsFinite = context.isFinite,
                                nativeJoin = arrayProto.join,
                                nativeKeys = overArg(Object.keys, Object),
                                nativeMax = Math.max,
                                nativeMin = Math.min,
                                nativeNow = Date.now,
                                nativeParseInt = context.parseInt,
                                nativeRandom = Math.random,
                                nativeReverse = arrayProto.reverse;

                            /* Built-in method references that are verified to be native. */
                            var DataView = getNative(context, 'DataView'),
                                Map = getNative(context, 'Map'),
                                Promise = getNative(context, 'Promise'),
                                Set = getNative(context, 'Set'),
                                WeakMap = getNative(context, 'WeakMap'),
                                nativeCreate = getNative(Object, 'create');

                            /** Used to store function metadata. */
                            var metaMap = WeakMap && new WeakMap;

                            /** Used to lookup unminified function names. */
                            var realNames = {};

                            /** Used to detect maps, sets, and weakmaps. */
                            var dataViewCtorString = toSource(DataView),
                                mapCtorString = toSource(Map),
                                promiseCtorString = toSource(Promise),
                                setCtorString = toSource(Set),
                                weakMapCtorString = toSource(WeakMap);

                            /** Used to convert symbols to primitives and strings. */
                            var symbolProto = Symbol ? Symbol.prototype : undefined,
                                symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
                                symbolToString = symbolProto ? symbolProto.toString : undefined;

                            /*------------------------------------------------------------------------*/

                            /**
                             * Creates a `lodash` object which wraps `value` to enable implicit method
                             * chain sequences. Methods that operate on and return arrays, collections,
                             * and functions can be chained together. Methods that retrieve a single value
                             * or may return a primitive value will automatically end the chain sequence
                             * and return the unwrapped value. Otherwise, the value must be unwrapped
                             * with `_#value`.
                             *
                             * Explicit chain sequences, which must be unwrapped with `_#value`, may be
                             * enabled using `_.chain`.
                             *
                             * The execution of chained methods is lazy, that is, it's deferred until
                             * `_#value` is implicitly or explicitly called.
                             *
                             * Lazy evaluation allows several methods to support shortcut fusion.
                             * Shortcut fusion is an optimization to merge iteratee calls; this avoids
                             * the creation of intermediate arrays and can greatly reduce the number of
                             * iteratee executions. Sections of a chain sequence qualify for shortcut
                             * fusion if the section is applied to an array and iteratees accept only
                             * one argument. The heuristic for whether a section qualifies for shortcut
                             * fusion is subject to change.
                             *
                             * Chaining is supported in custom builds as long as the `_#value` method is
                             * directly or indirectly included in the build.
                             *
                             * In addition to lodash methods, wrappers have `Array` and `String` methods.
                             *
                             * The wrapper `Array` methods are:
                             * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
                             *
                             * The wrapper `String` methods are:
                             * `replace` and `split`
                             *
                             * The wrapper methods that support shortcut fusion are:
                             * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
                             * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
                             * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
                             *
                             * The chainable wrapper methods are:
                             * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
                             * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
                             * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
                             * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
                             * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
                             * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
                             * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
                             * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
                             * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
                             * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
                             * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
                             * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
                             * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
                             * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
                             * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
                             * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
                             * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
                             * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
                             * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
                             * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
                             * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
                             * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
                             * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
                             * `zipObject`, `zipObjectDeep`, and `zipWith`
                             *
                             * The wrapper methods that are **not** chainable by default are:
                             * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
                             * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`,
                             * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`,
                             * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`,
                             * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`,
                             * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`,
                             * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`,
                             * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`,
                             * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`,
                             * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`,
                             * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`,
                             * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`,
                             * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`,
                             * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`,
                             * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`,
                             * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`,
                             * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`,
                             * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`,
                             * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`,
                             * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`,
                             * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`,
                             * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`,
                             * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`,
                             * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`,
                             * `upperFirst`, `value`, and `words`
                             *
                             * @name _
                             * @constructor
                             * @category Seq
                             * @param {*} value The value to wrap in a `lodash` instance.
                             * @returns {Object} Returns the new `lodash` wrapper instance.
                             * @example
                             *
                             * function square(n) {
                             *   return n * n;
                             * }
                             *
                             * var wrapped = _([1, 2, 3]);
                             *
                             * // Returns an unwrapped value.
                             * wrapped.reduce(_.add);
                             * // => 6
                             *
                             * // Returns a wrapped value.
                             * var squares = wrapped.map(square);
                             *
                             * _.isArray(squares);
                             * // => false
                             *
                             * _.isArray(squares.value());
                             * // => true
                             */
                            function lodash(value) {
                                if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
                                    if (value instanceof LodashWrapper) {
                                        return value;
                                    }
                                    if (hasOwnProperty.call(value, '__wrapped__')) {
                                        return wrapperClone(value);
                                    }
                                }
                                return new LodashWrapper(value);
                            }

                            /**
                             * The base implementation of `_.create` without support for assigning
                             * properties to the created object.
                             *
                             * @private
                             * @param {Object} proto The object to inherit from.
                             * @returns {Object} Returns the new object.
                             */
                            var baseCreate = (function () {
                                function object() { }
                                return function (proto) {
                                    if (!isObject(proto)) {
                                        return {};
                                    }
                                    if (objectCreate) {
                                        return objectCreate(proto);
                                    }
                                    object.prototype = proto;
                                    var result = new object;
                                    object.prototype = undefined;
                                    return result;
                                };
                            }());

                            /**
                             * The function whose prototype chain sequence wrappers inherit from.
                             *
                             * @private
                             */
                            function baseLodash() {
                                // No operation performed.
                            }

                            /**
                             * The base constructor for creating `lodash` wrapper objects.
                             *
                             * @private
                             * @param {*} value The value to wrap.
                             * @param {boolean} [chainAll] Enable explicit method chain sequences.
                             */
                            function LodashWrapper(value, chainAll) {
                                this.__wrapped__ = value;
                                this.__actions__ = [];
                                this.__chain__ = !!chainAll;
                                this.__index__ = 0;
                                this.__values__ = undefined;
                            }

                            /**
                             * By default, the template delimiters used by lodash are like those in
                             * embedded Ruby (ERB) as well as ES2015 template strings. Change the
                             * following template settings to use alternative delimiters.
                             *
                             * @static
                             * @memberOf _
                             * @type {Object}
                             */
                            lodash.templateSettings = {

                                /**
                                 * Used to detect `data` property values to be HTML-escaped.
                                 *
                                 * @memberOf _.templateSettings
                                 * @type {RegExp}
                                 */
                                'escape': reEscape,

                                /**
                                 * Used to detect code to be evaluated.
                                 *
                                 * @memberOf _.templateSettings
                                 * @type {RegExp}
                                 */
                                'evaluate': reEvaluate,

                                /**
                                 * Used to detect `data` property values to inject.
                                 *
                                 * @memberOf _.templateSettings
                                 * @type {RegExp}
                                 */
                                'interpolate': reInterpolate,

                                /**
                                 * Used to reference the data object in the template text.
                                 *
                                 * @memberOf _.templateSettings
                                 * @type {string}
                                 */
                                'variable': '',

                                /**
                                 * Used to import variables into the compiled template.
                                 *
                                 * @memberOf _.templateSettings
                                 * @type {Object}
                                 */
                                'imports': {

                                    /**
                                     * A reference to the `lodash` function.
                                     *
                                     * @memberOf _.templateSettings.imports
                                     * @type {Function}
                                     */
                                    '_': lodash
                                }
                            };

                            // Ensure wrappers are instances of `baseLodash`.
                            lodash.prototype = baseLodash.prototype;
                            lodash.prototype.constructor = lodash;

                            LodashWrapper.prototype = baseCreate(baseLodash.prototype);
                            LodashWrapper.prototype.constructor = LodashWrapper;

                            /*------------------------------------------------------------------------*/

                            /**
                             * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
                             *
                             * @private
                             * @constructor
                             * @param {*} value The value to wrap.
                             */
                            function LazyWrapper(value) {
                                this.__wrapped__ = value;
                                this.__actions__ = [];
                                this.__dir__ = 1;
                                this.__filtered__ = false;
                                this.__iteratees__ = [];
                                this.__takeCount__ = MAX_ARRAY_LENGTH;
                                this.__views__ = [];
                            }

                            /**
                             * Creates a clone of the lazy wrapper object.
                             *
                             * @private
                             * @name clone
                             * @memberOf LazyWrapper
                             * @returns {Object} Returns the cloned `LazyWrapper` object.
                             */
                            function lazyClone() {
                                var result = new LazyWrapper(this.__wrapped__);
                                result.__actions__ = copyArray(this.__actions__);
                                result.__dir__ = this.__dir__;
                                result.__filtered__ = this.__filtered__;
                                result.__iteratees__ = copyArray(this.__iteratees__);
                                result.__takeCount__ = this.__takeCount__;
                                result.__views__ = copyArray(this.__views__);
                                return result;
                            }

                            /**
                             * Reverses the direction of lazy iteration.
                             *
                             * @private
                             * @name reverse
                             * @memberOf LazyWrapper
                             * @returns {Object} Returns the new reversed `LazyWrapper` object.
                             */
                            function lazyReverse() {
                                if (this.__filtered__) {
                                    var result = new LazyWrapper(this);
                                    result.__dir__ = -1;
                                    result.__filtered__ = true;
                                } else {
                                    result = this.clone();
                                    result.__dir__ *= -1;
                                }
                                return result;
                            }

                            /**
                             * Extracts the unwrapped value from its lazy wrapper.
                             *
                             * @private
                             * @name value
                             * @memberOf LazyWrapper
                             * @returns {*} Returns the unwrapped value.
                             */
                            function lazyValue() {
                                var array = this.__wrapped__.value(),
                                    dir = this.__dir__,
                                    isArr = isArray(array),
                                    isRight = dir < 0,
                                    arrLength = isArr ? array.length : 0,
                                    view = getView(0, arrLength, this.__views__),
                                    start = view.start,
                                    end = view.end,
                                    length = end - start,
                                    index = isRight ? end : (start - 1),
                                    iteratees = this.__iteratees__,
                                    iterLength = iteratees.length,
                                    resIndex = 0,
                                    takeCount = nativeMin(length, this.__takeCount__);

                                if (!isArr || (!isRight && arrLength == length && takeCount == length)) {
                                    return baseWrapperValue(array, this.__actions__);
                                }
                                var result = [];

                                outer:
                                while (length-- && resIndex < takeCount) {
                                    index += dir;

                                    var iterIndex = -1,
                                        value = array[index];

                                    while (++iterIndex < iterLength) {
                                        var data = iteratees[iterIndex],
                                            iteratee = data.iteratee,
                                            type = data.type,
                                            computed = iteratee(value);

                                        if (type == LAZY_MAP_FLAG) {
                                            value = computed;
                                        } else if (!computed) {
                                            if (type == LAZY_FILTER_FLAG) {
                                                continue outer;
                                            } else {
                                                break outer;
                                            }
                                        }
                                    }
                                    result[resIndex++] = value;
                                }
                                return result;
                            }

                            // Ensure `LazyWrapper` is an instance of `baseLodash`.
                            LazyWrapper.prototype = baseCreate(baseLodash.prototype);
                            LazyWrapper.prototype.constructor = LazyWrapper;

                            /*------------------------------------------------------------------------*/

                            /**
                             * Creates a hash object.
                             *
                             * @private
                             * @constructor
                             * @param {Array} [entries] The key-value pairs to cache.
                             */
                            function Hash(entries) {
                                var index = -1,
                                    length = entries == null ? 0 : entries.length;

                                this.clear();
                                while (++index < length) {
                                    var entry = entries[index];
                                    this.set(entry[0], entry[1]);
                                }
                            }

                            /**
                             * Removes all key-value entries from the hash.
                             *
                             * @private
                             * @name clear
                             * @memberOf Hash
                             */
                            function hashClear() {
                                this.__data__ = nativeCreate ? nativeCreate(null) : {};
                                this.size = 0;
                            }

                            /**
                             * Removes `key` and its value from the hash.
                             *
                             * @private
                             * @name delete
                             * @memberOf Hash
                             * @param {Object} hash The hash to modify.
                             * @param {string} key The key of the value to remove.
                             * @returns {boolean} Returns `true` if the entry was removed, else `false`.
                             */
                            function hashDelete(key) {
                                var result = this.has(key) && delete this.__data__[key];
                                this.size -= result ? 1 : 0;
                                return result;
                            }

                            /**
                             * Gets the hash value for `key`.
                             *
                             * @private
                             * @name get
                             * @memberOf Hash
                             * @param {string} key The key of the value to get.
                             * @returns {*} Returns the entry value.
                             */
                            function hashGet(key) {
                                var data = this.__data__;
                                if (nativeCreate) {
                                    var result = data[key];
                                    return result === HASH_UNDEFINED ? undefined : result;
                                }
                                return hasOwnProperty.call(data, key) ? data[key] : undefined;
                            }

                            /**
                             * Checks if a hash value for `key` exists.
                             *
                             * @private
                             * @name has
                             * @memberOf Hash
                             * @param {string} key The key of the entry to check.
                             * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
                             */
                            function hashHas(key) {
                                var data = this.__data__;
                                return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);
                            }

                            /**
                             * Sets the hash `key` to `value`.
                             *
                             * @private
                             * @name set
                             * @memberOf Hash
                             * @param {string} key The key of the value to set.
                             * @param {*} value The value to set.
                             * @returns {Object} Returns the hash instance.
                             */
                            function hashSet(key, value) {
                                var data = this.__data__;
                                this.size += this.has(key) ? 0 : 1;
                                data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
                                return this;
                            }

                            // Add methods to `Hash`.
                            Hash.prototype.clear = hashClear;
                            Hash.prototype['delete'] = hashDelete;
                            Hash.prototype.get = hashGet;
                            Hash.prototype.has = hashHas;
                            Hash.prototype.set = hashSet;

                            /*------------------------------------------------------------------------*/

                            /**
                             * Creates an list cache object.
                             *
                             * @private
                             * @constructor
                             * @param {Array} [entries] The key-value pairs to cache.
                             */
                            function ListCache(entries) {
                                var index = -1,
                                    length = entries == null ? 0 : entries.length;

                                this.clear();
                                while (++index < length) {
                                    var entry = entries[index];
                                    this.set(entry[0], entry[1]);
                                }
                            }

                            /**
                             * Removes all key-value entries from the list cache.
                             *
                             * @private
                             * @name clear
                             * @memberOf ListCache
                             */
                            function listCacheClear() {
                                this.__data__ = [];
                                this.size = 0;
                            }

                            /**
                             * Removes `key` and its value from the list cache.
                             *
                             * @private
                             * @name delete
                             * @memberOf ListCache
                             * @param {string} key The key of the value to remove.
                             * @returns {boolean} Returns `true` if the entry was removed, else `false`.
                             */
                            function listCacheDelete(key) {
                                var data = this.__data__,
                                    index = assocIndexOf(data, key);

                                if (index < 0) {
                                    return false;
                                }
                                var lastIndex = data.length - 1;
                                if (index == lastIndex) {
                                    data.pop();
                                } else {
                                    splice.call(data, index, 1);
                                }
                                --this.size;
                                return true;
                            }

                            /**
                             * Gets the list cache value for `key`.
                             *
                             * @private
                             * @name get
                             * @memberOf ListCache
                             * @param {string} key The key of the value to get.
                             * @returns {*} Returns the entry value.
                             */
                            function listCacheGet(key) {
                                var data = this.__data__,
                                    index = assocIndexOf(data, key);

                                return index < 0 ? undefined : data[index][1];
                            }

                            /**
                             * Checks if a list cache value for `key` exists.
                             *
                             * @private
                             * @name has
                             * @memberOf ListCache
                             * @param {string} key The key of the entry to check.
                             * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
                             */
                            function listCacheHas(key) {
                                return assocIndexOf(this.__data__, key) > -1;
                            }

                            /**
                             * Sets the list cache `key` to `value`.
                             *
                             * @private
                             * @name set
                             * @memberOf ListCache
                             * @param {string} key The key of the value to set.
                             * @param {*} value The value to set.
                             * @returns {Object} Returns the list cache instance.
                             */
                            function listCacheSet(key, value) {
                                var data = this.__data__,
                                    index = assocIndexOf(data, key);

                                if (index < 0) {
                                    ++this.size;
                                    data.push([key, value]);
                                } else {
                                    data[index][1] = value;
                                }
                                return this;
                            }

                            // Add methods to `ListCache`.
                            ListCache.prototype.clear = listCacheClear;
                            ListCache.prototype['delete'] = listCacheDelete;
                            ListCache.prototype.get = listCacheGet;
                            ListCache.prototype.has = listCacheHas;
                            ListCache.prototype.set = listCacheSet;

                            /*------------------------------------------------------------------------*/

                            /**
                             * Creates a map cache object to store key-value pairs.
                             *
                             * @private
                             * @constructor
                             * @param {Array} [entries] The key-value pairs to cache.
                             */
                            function MapCache(entries) {
                                var index = -1,
                                    length = entries == null ? 0 : entries.length;

                                this.clear();
                                while (++index < length) {
                                    var entry = entries[index];
                                    this.set(entry[0], entry[1]);
                                }
                            }

                            /**
                             * Removes all key-value entries from the map.
                             *
                             * @private
                             * @name clear
                             * @memberOf MapCache
                             */
                            function mapCacheClear() {
                                this.size = 0;
                                this.__data__ = {
                                    'hash': new Hash,
                                    'map': new (Map || ListCache),
                                    'string': new Hash
                                };
                            }

                            /**
                             * Removes `key` and its value from the map.
                             *
                             * @private
                             * @name delete
                             * @memberOf MapCache
                             * @param {string} key The key of the value to remove.
                             * @returns {boolean} Returns `true` if the entry was removed, else `false`.
                             */
                            function mapCacheDelete(key) {
                                var result = getMapData(this, key)['delete'](key);
                                this.size -= result ? 1 : 0;
                                return result;
                            }

                            /**
                             * Gets the map value for `key`.
                             *
                             * @private
                             * @name get
                             * @memberOf MapCache
                             * @param {string} key The key of the value to get.
                             * @returns {*} Returns the entry value.
                             */
                            function mapCacheGet(key) {
                                return getMapData(this, key).get(key);
                            }

                            /**
                             * Checks if a map value for `key` exists.
                             *
                             * @private
                             * @name has
                             * @memberOf MapCache
                             * @param {string} key The key of the entry to check.
                             * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
                             */
                            function mapCacheHas(key) {
                                return getMapData(this, key).has(key);
                            }

                            /**
                             * Sets the map `key` to `value`.
                             *
                             * @private
                             * @name set
                             * @memberOf MapCache
                             * @param {string} key The key of the value to set.
                             * @param {*} value The value to set.
                             * @returns {Object} Returns the map cache instance.
                             */
                            function mapCacheSet(key, value) {
                                var data = getMapData(this, key),
                                    size = data.size;

                                data.set(key, value);
                                this.size += data.size == size ? 0 : 1;
                                return this;
                            }

                            // Add methods to `MapCache`.
                            MapCache.prototype.clear = mapCacheClear;
                            MapCache.prototype['delete'] = mapCacheDelete;
                            MapCache.prototype.get = mapCacheGet;
                            MapCache.prototype.has = mapCacheHas;
                            MapCache.prototype.set = mapCacheSet;

                            /*------------------------------------------------------------------------*/

                            /**
                             *
                             * Creates an array cache object to store unique values.
                             *
                             * @private
                             * @constructor
                             * @param {Array} [values] The values to cache.
                             */
                            function SetCache(values) {
                                var index = -1,
                                    length = values == null ? 0 : values.length;

                                this.__data__ = new MapCache;
                                while (++index < length) {
                                    this.add(values[index]);
                                }
                            }

                            /**
                             * Adds `value` to the array cache.
                             *
                             * @private
                             * @name add
                             * @memberOf SetCache
                             * @alias push
                             * @param {*} value The value to cache.
                             * @returns {Object} Returns the cache instance.
                             */
                            function setCacheAdd(value) {
                                this.__data__.set(value, HASH_UNDEFINED);
                                return this;
                            }

                            /**
                             * Checks if `value` is in the array cache.
                             *
                             * @private
                             * @name has
                             * @memberOf SetCache
                             * @param {*} value The value to search for.
                             * @returns {number} Returns `true` if `value` is found, else `false`.
                             */
                            function setCacheHas(value) {
                                return this.__data__.has(value);
                            }

                            // Add methods to `SetCache`.
                            SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
                            SetCache.prototype.has = setCacheHas;

                            /*------------------------------------------------------------------------*/

                            /**
                             * Creates a stack cache object to store key-value pairs.
                             *
                             * @private
                             * @constructor
                             * @param {Array} [entries] The key-value pairs to cache.
                             */
                            function Stack(entries) {
                                var data = this.__data__ = new ListCache(entries);
                                this.size = data.size;
                            }

                            /**
                             * Removes all key-value entries from the stack.
                             *
                             * @private
                             * @name clear
                             * @memberOf Stack
                             */
                            function stackClear() {
                                this.__data__ = new ListCache;
                                this.size = 0;
                            }

                            /**
                             * Removes `key` and its value from the stack.
                             *
                             * @private
                             * @name delete
                             * @memberOf Stack
                             * @param {string} key The key of the value to remove.
                             * @returns {boolean} Returns `true` if the entry was removed, else `false`.
                             */
                            function stackDelete(key) {
                                var data = this.__data__,
                                    result = data['delete'](key);

                                this.size = data.size;
                                return result;
                            }

                            /**
                             * Gets the stack value for `key`.
                             *
                             * @private
                             * @name get
                             * @memberOf Stack
                             * @param {string} key The key of the value to get.
                             * @returns {*} Returns the entry value.
                             */
                            function stackGet(key) {
                                return this.__data__.get(key);
                            }

                            /**
                             * Checks if a stack value for `key` exists.
                             *
                             * @private
                             * @name has
                             * @memberOf Stack
                             * @param {string} key The key of the entry to check.
                             * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
                             */
                            function stackHas(key) {
                                return this.__data__.has(key);
                            }

                            /**
                             * Sets the stack `key` to `value`.
                             *
                             * @private
                             * @name set
                             * @memberOf Stack
                             * @param {string} key The key of the value to set.
                             * @param {*} value The value to set.
                             * @returns {Object} Returns the stack cache instance.
                             */
                            function stackSet(key, value) {
                                var data = this.__data__;
                                if (data instanceof ListCache) {
                                    var pairs = data.__data__;
                                    if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
                                        pairs.push([key, value]);
                                        this.size = ++data.size;
                                        return this;
                                    }
                                    data = this.__data__ = new MapCache(pairs);
                                }
                                data.set(key, value);
                                this.size = data.size;
                                return this;
                            }

                            // Add methods to `Stack`.
                            Stack.prototype.clear = stackClear;
                            Stack.prototype['delete'] = stackDelete;
                            Stack.prototype.get = stackGet;
                            Stack.prototype.has = stackHas;
                            Stack.prototype.set = stackSet;

                            /*------------------------------------------------------------------------*/

                            /**
                             * Creates an array of the enumerable property names of the array-like `value`.
                             *
                             * @private
                             * @param {*} value The value to query.
                             * @param {boolean} inherited Specify returning inherited property names.
                             * @returns {Array} Returns the array of property names.
                             */
                            function arrayLikeKeys(value, inherited) {
                                var isArr = isArray(value),
                                    isArg = !isArr && isArguments(value),
                                    isBuff = !isArr && !isArg && isBuffer(value),
                                    isType = !isArr && !isArg && !isBuff && isTypedArray(value),
                                    skipIndexes = isArr || isArg || isBuff || isType,
                                    result = skipIndexes ? baseTimes(value.length, String) : [],
                                    length = result.length;

                                for (var key in value) {
                                    if ((inherited || hasOwnProperty.call(value, key)) &&
                                        !(skipIndexes && (
                                            // Safari 9 has enumerable `arguments.length` in strict mode.
                                            key == 'length' ||
                                            // Node.js 0.10 has enumerable non-index properties on buffers.
                                            (isBuff && (key == 'offset' || key == 'parent')) ||
                                            // PhantomJS 2 has enumerable non-index properties on typed arrays.
                                            (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
                                            // Skip index properties.
                                            isIndex(key, length)
                                        ))) {
                                        result.push(key);
                                    }
                                }
                                return result;
                            }

                            /**
                             * A specialized version of `_.sample` for arrays.
                             *
                             * @private
                             * @param {Array} array The array to sample.
                             * @returns {*} Returns the random element.
                             */
                            function arraySample(array) {
                                var length = array.length;
                                return length ? array[baseRandom(0, length - 1)] : undefined;
                            }

                            /**
                             * A specialized version of `_.sampleSize` for arrays.
                             *
                             * @private
                             * @param {Array} array The array to sample.
                             * @param {number} n The number of elements to sample.
                             * @returns {Array} Returns the random elements.
                             */
                            function arraySampleSize(array, n) {
                                return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length));
                            }

                            /**
                             * A specialized version of `_.shuffle` for arrays.
                             *
                             * @private
                             * @param {Array} array The array to shuffle.
                             * @returns {Array} Returns the new shuffled array.
                             */
                            function arrayShuffle(array) {
                                return shuffleSelf(copyArray(array));
                            }

                            /**
                             * This function is like `assignValue` except that it doesn't assign
                             * `undefined` values.
                             *
                             * @private
                             * @param {Object} object The object to modify.
                             * @param {string} key The key of the property to assign.
                             * @param {*} value The value to assign.
                             */
                            function assignMergeValue(object, key, value) {
                                if ((value !== undefined && !eq(object[key], value)) ||
                                    (value === undefined && !(key in object))) {
                                    baseAssignValue(object, key, value);
                                }
                            }

                            /**
                             * Assigns `value` to `key` of `object` if the existing value is not equivalent
                             * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
                             * for equality comparisons.
                             *
                             * @private
                             * @param {Object} object The object to modify.
                             * @param {string} key The key of the property to assign.
                             * @param {*} value The value to assign.
                             */
                            function assignValue(object, key, value) {
                                var objValue = object[key];
                                if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
                                    (value === undefined && !(key in object))) {
                                    baseAssignValue(object, key, value);
                                }
                            }

                            /**
                             * Gets the index at which the `key` is found in `array` of key-value pairs.
                             *
                             * @private
                             * @param {Array} array The array to inspect.
                             * @param {*} key The key to search for.
                             * @returns {number} Returns the index of the matched value, else `-1`.
                             */
                            function assocIndexOf(array, key) {
                                var length = array.length;
                                while (length--) {
                                    if (eq(array[length][0], key)) {
                                        return length;
                                    }
                                }
                                return -1;
                            }

                            /**
                             * Aggregates elements of `collection` on `accumulator` with keys transformed
                             * by `iteratee` and values set by `setter`.
                             *
                             * @private
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} setter The function to set `accumulator` values.
                             * @param {Function} iteratee The iteratee to transform keys.
                             * @param {Object} accumulator The initial aggregated object.
                             * @returns {Function} Returns `accumulator`.
                             */
                            function baseAggregator(collection, setter, iteratee, accumulator) {
                                baseEach(collection, function (value, key, collection) {
                                    setter(accumulator, value, iteratee(value), collection);
                                });
                                return accumulator;
                            }

                            /**
                             * The base implementation of `_.assign` without support for multiple sources
                             * or `customizer` functions.
                             *
                             * @private
                             * @param {Object} object The destination object.
                             * @param {Object} source The source object.
                             * @returns {Object} Returns `object`.
                             */
                            function baseAssign(object, source) {
                                return object && copyObject(source, keys(source), object);
                            }

                            /**
                             * The base implementation of `_.assignIn` without support for multiple sources
                             * or `customizer` functions.
                             *
                             * @private
                             * @param {Object} object The destination object.
                             * @param {Object} source The source object.
                             * @returns {Object} Returns `object`.
                             */
                            function baseAssignIn(object, source) {
                                return object && copyObject(source, keysIn(source), object);
                            }

                            /**
                             * The base implementation of `assignValue` and `assignMergeValue` without
                             * value checks.
                             *
                             * @private
                             * @param {Object} object The object to modify.
                             * @param {string} key The key of the property to assign.
                             * @param {*} value The value to assign.
                             */
                            function baseAssignValue(object, key, value) {
                                if (key == '__proto__' && defineProperty) {
                                    defineProperty(object, key, {
                                        'configurable': true,
                                        'enumerable': true,
                                        'value': value,
                                        'writable': true
                                    });
                                } else {
                                    object[key] = value;
                                }
                            }

                            /**
                             * The base implementation of `_.at` without support for individual paths.
                             *
                             * @private
                             * @param {Object} object The object to iterate over.
                             * @param {string[]} paths The property paths to pick.
                             * @returns {Array} Returns the picked elements.
                             */
                            function baseAt(object, paths) {
                                var index = -1,
                                    length = paths.length,
                                    result = Array(length),
                                    skip = object == null;

                                while (++index < length) {
                                    result[index] = skip ? undefined : get(object, paths[index]);
                                }
                                return result;
                            }

                            /**
                             * The base implementation of `_.clamp` which doesn't coerce arguments.
                             *
                             * @private
                             * @param {number} number The number to clamp.
                             * @param {number} [lower] The lower bound.
                             * @param {number} upper The upper bound.
                             * @returns {number} Returns the clamped number.
                             */
                            function baseClamp(number, lower, upper) {
                                if (number === number) {
                                    if (upper !== undefined) {
                                        number = number <= upper ? number : upper;
                                    }
                                    if (lower !== undefined) {
                                        number = number >= lower ? number : lower;
                                    }
                                }
                                return number;
                            }

                            /**
                             * The base implementation of `_.clone` and `_.cloneDeep` which tracks
                             * traversed objects.
                             *
                             * @private
                             * @param {*} value The value to clone.
                             * @param {boolean} bitmask The bitmask flags.
                             *  1 - Deep clone
                             *  2 - Flatten inherited properties
                             *  4 - Clone symbols
                             * @param {Function} [customizer] The function to customize cloning.
                             * @param {string} [key] The key of `value`.
                             * @param {Object} [object] The parent object of `value`.
                             * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
                             * @returns {*} Returns the cloned value.
                             */
                            function baseClone(value, bitmask, customizer, key, object, stack) {
                                var result,
                                    isDeep = bitmask & CLONE_DEEP_FLAG,
                                    isFlat = bitmask & CLONE_FLAT_FLAG,
                                    isFull = bitmask & CLONE_SYMBOLS_FLAG;

                                if (customizer) {
                                    result = object ? customizer(value, key, object, stack) : customizer(value);
                                }
                                if (result !== undefined) {
                                    return result;
                                }
                                if (!isObject(value)) {
                                    return value;
                                }
                                var isArr = isArray(value);
                                if (isArr) {
                                    result = initCloneArray(value);
                                    if (!isDeep) {
                                        return copyArray(value, result);
                                    }
                                } else {
                                    var tag = getTag(value),
                                        isFunc = tag == funcTag || tag == genTag;

                                    if (isBuffer(value)) {
                                        return cloneBuffer(value, isDeep);
                                    }
                                    if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
                                        result = (isFlat || isFunc) ? {} : initCloneObject(value);
                                        if (!isDeep) {
                                            return isFlat
                                                ? copySymbolsIn(value, baseAssignIn(result, value))
                                                : copySymbols(value, baseAssign(result, value));
                                        }
                                    } else {
                                        if (!cloneableTags[tag]) {
                                            return object ? value : {};
                                        }
                                        result = initCloneByTag(value, tag, isDeep);
                                    }
                                }
                                // Check for circular references and return its corresponding clone.
                                stack || (stack = new Stack);
                                var stacked = stack.get(value);
                                if (stacked) {
                                    return stacked;
                                }
                                stack.set(value, result);

                                if (isSet(value)) {
                                    value.forEach(function (subValue) {
                                        result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));
                                    });
                                } else if (isMap(value)) {
                                    value.forEach(function (subValue, key) {
                                        result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));
                                    });
                                }

                                var keysFunc = isFull
                                    ? (isFlat ? getAllKeysIn : getAllKeys)
                                    : (isFlat ? keysIn : keys);

                                var props = isArr ? undefined : keysFunc(value);
                                arrayEach(props || value, function (subValue, key) {
                                    if (props) {
                                        key = subValue;
                                        subValue = value[key];
                                    }
                                    // Recursively populate clone (susceptible to call stack limits).
                                    assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
                                });
                                return result;
                            }

                            /**
                             * The base implementation of `_.conforms` which doesn't clone `source`.
                             *
                             * @private
                             * @param {Object} source The object of property predicates to conform to.
                             * @returns {Function} Returns the new spec function.
                             */
                            function baseConforms(source) {
                                var props = keys(source);
                                return function (object) {
                                    return baseConformsTo(object, source, props);
                                };
                            }

                            /**
                             * The base implementation of `_.conformsTo` which accepts `props` to check.
                             *
                             * @private
                             * @param {Object} object The object to inspect.
                             * @param {Object} source The object of property predicates to conform to.
                             * @returns {boolean} Returns `true` if `object` conforms, else `false`.
                             */
                            function baseConformsTo(object, source, props) {
                                var length = props.length;
                                if (object == null) {
                                    return !length;
                                }
                                object = Object(object);
                                while (length--) {
                                    var key = props[length],
                                        predicate = source[key],
                                        value = object[key];

                                    if ((value === undefined && !(key in object)) || !predicate(value)) {
                                        return false;
                                    }
                                }
                                return true;
                            }

                            /**
                             * The base implementation of `_.delay` and `_.defer` which accepts `args`
                             * to provide to `func`.
                             *
                             * @private
                             * @param {Function} func The function to delay.
                             * @param {number} wait The number of milliseconds to delay invocation.
                             * @param {Array} args The arguments to provide to `func`.
                             * @returns {number|Object} Returns the timer id or timeout object.
                             */
                            function baseDelay(func, wait, args) {
                                if (typeof func != 'function') {
                                    throw new TypeError(FUNC_ERROR_TEXT);
                                }
                                return setTimeout(function () { func.apply(undefined, args); }, wait);
                            }

                            /**
                             * The base implementation of methods like `_.difference` without support
                             * for excluding multiple arrays or iteratee shorthands.
                             *
                             * @private
                             * @param {Array} array The array to inspect.
                             * @param {Array} values The values to exclude.
                             * @param {Function} [iteratee] The iteratee invoked per element.
                             * @param {Function} [comparator] The comparator invoked per element.
                             * @returns {Array} Returns the new array of filtered values.
                             */
                            function baseDifference(array, values, iteratee, comparator) {
                                var index = -1,
                                    includes = arrayIncludes,
                                    isCommon = true,
                                    length = array.length,
                                    result = [],
                                    valuesLength = values.length;

                                if (!length) {
                                    return result;
                                }
                                if (iteratee) {
                                    values = arrayMap(values, baseUnary(iteratee));
                                }
                                if (comparator) {
                                    includes = arrayIncludesWith;
                                    isCommon = false;
                                }
                                else if (values.length >= LARGE_ARRAY_SIZE) {
                                    includes = cacheHas;
                                    isCommon = false;
                                    values = new SetCache(values);
                                }
                                outer:
                                while (++index < length) {
                                    var value = array[index],
                                        computed = iteratee == null ? value : iteratee(value);

                                    value = (comparator || value !== 0) ? value : 0;
                                    if (isCommon && computed === computed) {
                                        var valuesIndex = valuesLength;
                                        while (valuesIndex--) {
                                            if (values[valuesIndex] === computed) {
                                                continue outer;
                                            }
                                        }
                                        result.push(value);
                                    }
                                    else if (!includes(values, computed, comparator)) {
                                        result.push(value);
                                    }
                                }
                                return result;
                            }

                            /**
                             * The base implementation of `_.forEach` without support for iteratee shorthands.
                             *
                             * @private
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} iteratee The function invoked per iteration.
                             * @returns {Array|Object} Returns `collection`.
                             */
                            var baseEach = createBaseEach(baseForOwn);

                            /**
                             * The base implementation of `_.forEachRight` without support for iteratee shorthands.
                             *
                             * @private
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} iteratee The function invoked per iteration.
                             * @returns {Array|Object} Returns `collection`.
                             */
                            var baseEachRight = createBaseEach(baseForOwnRight, true);

                            /**
                             * The base implementation of `_.every` without support for iteratee shorthands.
                             *
                             * @private
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} predicate The function invoked per iteration.
                             * @returns {boolean} Returns `true` if all elements pass the predicate check,
                             *  else `false`
                             */
                            function baseEvery(collection, predicate) {
                                var result = true;
                                baseEach(collection, function (value, index, collection) {
                                    result = !!predicate(value, index, collection);
                                    return result;
                                });
                                return result;
                            }

                            /**
                             * The base implementation of methods like `_.max` and `_.min` which accepts a
                             * `comparator` to determine the extremum value.
                             *
                             * @private
                             * @param {Array} array The array to iterate over.
                             * @param {Function} iteratee The iteratee invoked per iteration.
                             * @param {Function} comparator The comparator used to compare values.
                             * @returns {*} Returns the extremum value.
                             */
                            function baseExtremum(array, iteratee, comparator) {
                                var index = -1,
                                    length = array.length;

                                while (++index < length) {
                                    var value = array[index],
                                        current = iteratee(value);

                                    if (current != null && (computed === undefined
                                        ? (current === current && !isSymbol(current))
                                        : comparator(current, computed)
                                    )) {
                                        var computed = current,
                                            result = value;
                                    }
                                }
                                return result;
                            }

                            /**
                             * The base implementation of `_.fill` without an iteratee call guard.
                             *
                             * @private
                             * @param {Array} array The array to fill.
                             * @param {*} value The value to fill `array` with.
                             * @param {number} [start=0] The start position.
                             * @param {number} [end=array.length] The end position.
                             * @returns {Array} Returns `array`.
                             */
                            function baseFill(array, value, start, end) {
                                var length = array.length;

                                start = toInteger(start);
                                if (start < 0) {
                                    start = -start > length ? 0 : (length + start);
                                }
                                end = (end === undefined || end > length) ? length : toInteger(end);
                                if (end < 0) {
                                    end += length;
                                }
                                end = start > end ? 0 : toLength(end);
                                while (start < end) {
                                    array[start++] = value;
                                }
                                return array;
                            }

                            /**
                             * The base implementation of `_.filter` without support for iteratee shorthands.
                             *
                             * @private
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} predicate The function invoked per iteration.
                             * @returns {Array} Returns the new filtered array.
                             */
                            function baseFilter(collection, predicate) {
                                var result = [];
                                baseEach(collection, function (value, index, collection) {
                                    if (predicate(value, index, collection)) {
                                        result.push(value);
                                    }
                                });
                                return result;
                            }

                            /**
                             * The base implementation of `_.flatten` with support for restricting flattening.
                             *
                             * @private
                             * @param {Array} array The array to flatten.
                             * @param {number} depth The maximum recursion depth.
                             * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
                             * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
                             * @param {Array} [result=[]] The initial result value.
                             * @returns {Array} Returns the new flattened array.
                             */
                            function baseFlatten(array, depth, predicate, isStrict, result) {
                                var index = -1,
                                    length = array.length;

                                predicate || (predicate = isFlattenable);
                                result || (result = []);

                                while (++index < length) {
                                    var value = array[index];
                                    if (depth > 0 && predicate(value)) {
                                        if (depth > 1) {
                                            // Recursively flatten arrays (susceptible to call stack limits).
                                            baseFlatten(value, depth - 1, predicate, isStrict, result);
                                        } else {
                                            arrayPush(result, value);
                                        }
                                    } else if (!isStrict) {
                                        result[result.length] = value;
                                    }
                                }
                                return result;
                            }

                            /**
                             * The base implementation of `baseForOwn` which iterates over `object`
                             * properties returned by `keysFunc` and invokes `iteratee` for each property.
                             * Iteratee functions may exit iteration early by explicitly returning `false`.
                             *
                             * @private
                             * @param {Object} object The object to iterate over.
                             * @param {Function} iteratee The function invoked per iteration.
                             * @param {Function} keysFunc The function to get the keys of `object`.
                             * @returns {Object} Returns `object`.
                             */
                            var baseFor = createBaseFor();

                            /**
                             * This function is like `baseFor` except that it iterates over properties
                             * in the opposite order.
                             *
                             * @private
                             * @param {Object} object The object to iterate over.
                             * @param {Function} iteratee The function invoked per iteration.
                             * @param {Function} keysFunc The function to get the keys of `object`.
                             * @returns {Object} Returns `object`.
                             */
                            var baseForRight = createBaseFor(true);

                            /**
                             * The base implementation of `_.forOwn` without support for iteratee shorthands.
                             *
                             * @private
                             * @param {Object} object The object to iterate over.
                             * @param {Function} iteratee The function invoked per iteration.
                             * @returns {Object} Returns `object`.
                             */
                            function baseForOwn(object, iteratee) {
                                return object && baseFor(object, iteratee, keys);
                            }

                            /**
                             * The base implementation of `_.forOwnRight` without support for iteratee shorthands.
                             *
                             * @private
                             * @param {Object} object The object to iterate over.
                             * @param {Function} iteratee The function invoked per iteration.
                             * @returns {Object} Returns `object`.
                             */
                            function baseForOwnRight(object, iteratee) {
                                return object && baseForRight(object, iteratee, keys);
                            }

                            /**
                             * The base implementation of `_.functions` which creates an array of
                             * `object` function property names filtered from `props`.
                             *
                             * @private
                             * @param {Object} object The object to inspect.
                             * @param {Array} props The property names to filter.
                             * @returns {Array} Returns the function names.
                             */
                            function baseFunctions(object, props) {
                                return arrayFilter(props, function (key) {
                                    return isFunction(object[key]);
                                });
                            }

                            /**
                             * The base implementation of `_.get` without support for default values.
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @param {Array|string} path The path of the property to get.
                             * @returns {*} Returns the resolved value.
                             */
                            function baseGet(object, path) {
                                path = castPath(path, object);

                                var index = 0,
                                    length = path.length;

                                while (object != null && index < length) {
                                    object = object[toKey(path[index++])];
                                }
                                return (index && index == length) ? object : undefined;
                            }

                            /**
                             * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
                             * `keysFunc` and `symbolsFunc` to get the enumerable property names and
                             * symbols of `object`.
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @param {Function} keysFunc The function to get the keys of `object`.
                             * @param {Function} symbolsFunc The function to get the symbols of `object`.
                             * @returns {Array} Returns the array of property names and symbols.
                             */
                            function baseGetAllKeys(object, keysFunc, symbolsFunc) {
                                var result = keysFunc(object);
                                return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
                            }

                            /**
                             * The base implementation of `getTag` without fallbacks for buggy environments.
                             *
                             * @private
                             * @param {*} value The value to query.
                             * @returns {string} Returns the `toStringTag`.
                             */
                            function baseGetTag(value) {
                                if (value == null) {
                                    return value === undefined ? undefinedTag : nullTag;
                                }
                                return (symToStringTag && symToStringTag in Object(value))
                                    ? getRawTag(value)
                                    : objectToString(value);
                            }

                            /**
                             * The base implementation of `_.gt` which doesn't coerce arguments.
                             *
                             * @private
                             * @param {*} value The value to compare.
                             * @param {*} other The other value to compare.
                             * @returns {boolean} Returns `true` if `value` is greater than `other`,
                             *  else `false`.
                             */
                            function baseGt(value, other) {
                                return value > other;
                            }

                            /**
                             * The base implementation of `_.has` without support for deep paths.
                             *
                             * @private
                             * @param {Object} [object] The object to query.
                             * @param {Array|string} key The key to check.
                             * @returns {boolean} Returns `true` if `key` exists, else `false`.
                             */
                            function baseHas(object, key) {
                                return object != null && hasOwnProperty.call(object, key);
                            }

                            /**
                             * The base implementation of `_.hasIn` without support for deep paths.
                             *
                             * @private
                             * @param {Object} [object] The object to query.
                             * @param {Array|string} key The key to check.
                             * @returns {boolean} Returns `true` if `key` exists, else `false`.
                             */
                            function baseHasIn(object, key) {
                                return object != null && key in Object(object);
                            }

                            /**
                             * The base implementation of `_.inRange` which doesn't coerce arguments.
                             *
                             * @private
                             * @param {number} number The number to check.
                             * @param {number} start The start of the range.
                             * @param {number} end The end of the range.
                             * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
                             */
                            function baseInRange(number, start, end) {
                                return number >= nativeMin(start, end) && number < nativeMax(start, end);
                            }

                            /**
                             * The base implementation of methods like `_.intersection`, without support
                             * for iteratee shorthands, that accepts an array of arrays to inspect.
                             *
                             * @private
                             * @param {Array} arrays The arrays to inspect.
                             * @param {Function} [iteratee] The iteratee invoked per element.
                             * @param {Function} [comparator] The comparator invoked per element.
                             * @returns {Array} Returns the new array of shared values.
                             */
                            function baseIntersection(arrays, iteratee, comparator) {
                                var includes = comparator ? arrayIncludesWith : arrayIncludes,
                                    length = arrays[0].length,
                                    othLength = arrays.length,
                                    othIndex = othLength,
                                    caches = Array(othLength),
                                    maxLength = Infinity,
                                    result = [];

                                while (othIndex--) {
                                    var array = arrays[othIndex];
                                    if (othIndex && iteratee) {
                                        array = arrayMap(array, baseUnary(iteratee));
                                    }
                                    maxLength = nativeMin(array.length, maxLength);
                                    caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
                                        ? new SetCache(othIndex && array)
                                        : undefined;
                                }
                                array = arrays[0];

                                var index = -1,
                                    seen = caches[0];

                                outer:
                                while (++index < length && result.length < maxLength) {
                                    var value = array[index],
                                        computed = iteratee ? iteratee(value) : value;

                                    value = (comparator || value !== 0) ? value : 0;
                                    if (!(seen
                                        ? cacheHas(seen, computed)
                                        : includes(result, computed, comparator)
                                    )) {
                                        othIndex = othLength;
                                        while (--othIndex) {
                                            var cache = caches[othIndex];
                                            if (!(cache
                                                ? cacheHas(cache, computed)
                                                : includes(arrays[othIndex], computed, comparator))
                                            ) {
                                                continue outer;
                                            }
                                        }
                                        if (seen) {
                                            seen.push(computed);
                                        }
                                        result.push(value);
                                    }
                                }
                                return result;
                            }

                            /**
                             * The base implementation of `_.invert` and `_.invertBy` which inverts
                             * `object` with values transformed by `iteratee` and set by `setter`.
                             *
                             * @private
                             * @param {Object} object The object to iterate over.
                             * @param {Function} setter The function to set `accumulator` values.
                             * @param {Function} iteratee The iteratee to transform values.
                             * @param {Object} accumulator The initial inverted object.
                             * @returns {Function} Returns `accumulator`.
                             */
                            function baseInverter(object, setter, iteratee, accumulator) {
                                baseForOwn(object, function (value, key, object) {
                                    setter(accumulator, iteratee(value), key, object);
                                });
                                return accumulator;
                            }

                            /**
                             * The base implementation of `_.invoke` without support for individual
                             * method arguments.
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @param {Array|string} path The path of the method to invoke.
                             * @param {Array} args The arguments to invoke the method with.
                             * @returns {*} Returns the result of the invoked method.
                             */
                            function baseInvoke(object, path, args) {
                                path = castPath(path, object);
                                object = parent(object, path);
                                var func = object == null ? object : object[toKey(last(path))];
                                return func == null ? undefined : apply(func, object, args);
                            }

                            /**
                             * The base implementation of `_.isArguments`.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is an `arguments` object,
                             */
                            function baseIsArguments(value) {
                                return isObjectLike(value) && baseGetTag(value) == argsTag;
                            }

                            /**
                             * The base implementation of `_.isArrayBuffer` without Node.js optimizations.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
                             */
                            function baseIsArrayBuffer(value) {
                                return isObjectLike(value) && baseGetTag(value) == arrayBufferTag;
                            }

                            /**
                             * The base implementation of `_.isDate` without Node.js optimizations.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
                             */
                            function baseIsDate(value) {
                                return isObjectLike(value) && baseGetTag(value) == dateTag;
                            }

                            /**
                             * The base implementation of `_.isEqual` which supports partial comparisons
                             * and tracks traversed objects.
                             *
                             * @private
                             * @param {*} value The value to compare.
                             * @param {*} other The other value to compare.
                             * @param {boolean} bitmask The bitmask flags.
                             *  1 - Unordered comparison
                             *  2 - Partial comparison
                             * @param {Function} [customizer] The function to customize comparisons.
                             * @param {Object} [stack] Tracks traversed `value` and `other` objects.
                             * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
                             */
                            function baseIsEqual(value, other, bitmask, customizer, stack) {
                                if (value === other) {
                                    return true;
                                }
                                if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {
                                    return value !== value && other !== other;
                                }
                                return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);
                            }

                            /**
                             * A specialized version of `baseIsEqual` for arrays and objects which performs
                             * deep comparisons and tracks traversed objects enabling objects with circular
                             * references to be compared.
                             *
                             * @private
                             * @param {Object} object The object to compare.
                             * @param {Object} other The other object to compare.
                             * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
                             * @param {Function} customizer The function to customize comparisons.
                             * @param {Function} equalFunc The function to determine equivalents of values.
                             * @param {Object} [stack] Tracks traversed `object` and `other` objects.
                             * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
                             */
                            function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
                                var objIsArr = isArray(object),
                                    othIsArr = isArray(other),
                                    objTag = objIsArr ? arrayTag : getTag(object),
                                    othTag = othIsArr ? arrayTag : getTag(other);

                                objTag = objTag == argsTag ? objectTag : objTag;
                                othTag = othTag == argsTag ? objectTag : othTag;

                                var objIsObj = objTag == objectTag,
                                    othIsObj = othTag == objectTag,
                                    isSameTag = objTag == othTag;

                                if (isSameTag && isBuffer(object)) {
                                    if (!isBuffer(other)) {
                                        return false;
                                    }
                                    objIsArr = true;
                                    objIsObj = false;
                                }
                                if (isSameTag && !objIsObj) {
                                    stack || (stack = new Stack);
                                    return (objIsArr || isTypedArray(object))
                                        ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)
                                        : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
                                }
                                if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
                                    var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
                                        othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');

                                    if (objIsWrapped || othIsWrapped) {
                                        var objUnwrapped = objIsWrapped ? object.value() : object,
                                            othUnwrapped = othIsWrapped ? other.value() : other;

                                        stack || (stack = new Stack);
                                        return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
                                    }
                                }
                                if (!isSameTag) {
                                    return false;
                                }
                                stack || (stack = new Stack);
                                return equalObjects(object, other, bitmask, customizer, equalFunc, stack);
                            }

                            /**
                             * The base implementation of `_.isMap` without Node.js optimizations.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a map, else `false`.
                             */
                            function baseIsMap(value) {
                                return isObjectLike(value) && getTag(value) == mapTag;
                            }

                            /**
                             * The base implementation of `_.isMatch` without support for iteratee shorthands.
                             *
                             * @private
                             * @param {Object} object The object to inspect.
                             * @param {Object} source The object of property values to match.
                             * @param {Array} matchData The property names, values, and compare flags to match.
                             * @param {Function} [customizer] The function to customize comparisons.
                             * @returns {boolean} Returns `true` if `object` is a match, else `false`.
                             */
                            function baseIsMatch(object, source, matchData, customizer) {
                                var index = matchData.length,
                                    length = index,
                                    noCustomizer = !customizer;

                                if (object == null) {
                                    return !length;
                                }
                                object = Object(object);
                                while (index--) {
                                    var data = matchData[index];
                                    if ((noCustomizer && data[2])
                                        ? data[1] !== object[data[0]]
                                        : !(data[0] in object)
                                    ) {
                                        return false;
                                    }
                                }
                                while (++index < length) {
                                    data = matchData[index];
                                    var key = data[0],
                                        objValue = object[key],
                                        srcValue = data[1];

                                    if (noCustomizer && data[2]) {
                                        if (objValue === undefined && !(key in object)) {
                                            return false;
                                        }
                                    } else {
                                        var stack = new Stack;
                                        if (customizer) {
                                            var result = customizer(objValue, srcValue, key, object, source, stack);
                                        }
                                        if (!(result === undefined
                                            ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack)
                                            : result
                                        )) {
                                            return false;
                                        }
                                    }
                                }
                                return true;
                            }

                            /**
                             * The base implementation of `_.isNative` without bad shim checks.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a native function,
                             *  else `false`.
                             */
                            function baseIsNative(value) {
                                if (!isObject(value) || isMasked(value)) {
                                    return false;
                                }
                                var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
                                return pattern.test(toSource(value));
                            }

                            /**
                             * The base implementation of `_.isRegExp` without Node.js optimizations.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
                             */
                            function baseIsRegExp(value) {
                                return isObjectLike(value) && baseGetTag(value) == regexpTag;
                            }

                            /**
                             * The base implementation of `_.isSet` without Node.js optimizations.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a set, else `false`.
                             */
                            function baseIsSet(value) {
                                return isObjectLike(value) && getTag(value) == setTag;
                            }

                            /**
                             * The base implementation of `_.isTypedArray` without Node.js optimizations.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
                             */
                            function baseIsTypedArray(value) {
                                return isObjectLike(value) &&
                                    isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
                            }

                            /**
                             * The base implementation of `_.iteratee`.
                             *
                             * @private
                             * @param {*} [value=_.identity] The value to convert to an iteratee.
                             * @returns {Function} Returns the iteratee.
                             */
                            function baseIteratee(value) {
                                // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
                                // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
                                if (typeof value == 'function') {
                                    return value;
                                }
                                if (value == null) {
                                    return identity;
                                }
                                if (typeof value == 'object') {
                                    return isArray(value)
                                        ? baseMatchesProperty(value[0], value[1])
                                        : baseMatches(value);
                                }
                                return property(value);
                            }

                            /**
                             * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @returns {Array} Returns the array of property names.
                             */
                            function baseKeys(object) {
                                if (!isPrototype(object)) {
                                    return nativeKeys(object);
                                }
                                var result = [];
                                for (var key in Object(object)) {
                                    if (hasOwnProperty.call(object, key) && key != 'constructor') {
                                        result.push(key);
                                    }
                                }
                                return result;
                            }

                            /**
                             * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @returns {Array} Returns the array of property names.
                             */
                            function baseKeysIn(object) {
                                if (!isObject(object)) {
                                    return nativeKeysIn(object);
                                }
                                var isProto = isPrototype(object),
                                    result = [];

                                for (var key in object) {
                                    if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
                                        result.push(key);
                                    }
                                }
                                return result;
                            }

                            /**
                             * The base implementation of `_.lt` which doesn't coerce arguments.
                             *
                             * @private
                             * @param {*} value The value to compare.
                             * @param {*} other The other value to compare.
                             * @returns {boolean} Returns `true` if `value` is less than `other`,
                             *  else `false`.
                             */
                            function baseLt(value, other) {
                                return value < other;
                            }

                            /**
                             * The base implementation of `_.map` without support for iteratee shorthands.
                             *
                             * @private
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} iteratee The function invoked per iteration.
                             * @returns {Array} Returns the new mapped array.
                             */
                            function baseMap(collection, iteratee) {
                                var index = -1,
                                    result = isArrayLike(collection) ? Array(collection.length) : [];

                                baseEach(collection, function (value, key, collection) {
                                    result[++index] = iteratee(value, key, collection);
                                });
                                return result;
                            }

                            /**
                             * The base implementation of `_.matches` which doesn't clone `source`.
                             *
                             * @private
                             * @param {Object} source The object of property values to match.
                             * @returns {Function} Returns the new spec function.
                             */
                            function baseMatches(source) {
                                var matchData = getMatchData(source);
                                if (matchData.length == 1 && matchData[0][2]) {
                                    return matchesStrictComparable(matchData[0][0], matchData[0][1]);
                                }
                                return function (object) {
                                    return object === source || baseIsMatch(object, source, matchData);
                                };
                            }

                            /**
                             * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
                             *
                             * @private
                             * @param {string} path The path of the property to get.
                             * @param {*} srcValue The value to match.
                             * @returns {Function} Returns the new spec function.
                             */
                            function baseMatchesProperty(path, srcValue) {
                                if (isKey(path) && isStrictComparable(srcValue)) {
                                    return matchesStrictComparable(toKey(path), srcValue);
                                }
                                return function (object) {
                                    var objValue = get(object, path);
                                    return (objValue === undefined && objValue === srcValue)
                                        ? hasIn(object, path)
                                        : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
                                };
                            }

                            /**
                             * The base implementation of `_.merge` without support for multiple sources.
                             *
                             * @private
                             * @param {Object} object The destination object.
                             * @param {Object} source The source object.
                             * @param {number} srcIndex The index of `source`.
                             * @param {Function} [customizer] The function to customize merged values.
                             * @param {Object} [stack] Tracks traversed source values and their merged
                             *  counterparts.
                             */
                            function baseMerge(object, source, srcIndex, customizer, stack) {
                                if (object === source) {
                                    return;
                                }
                                baseFor(source, function (srcValue, key) {
                                    stack || (stack = new Stack);
                                    if (isObject(srcValue)) {
                                        baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
                                    }
                                    else {
                                        var newValue = customizer
                                            ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack)
                                            : undefined;

                                        if (newValue === undefined) {
                                            newValue = srcValue;
                                        }
                                        assignMergeValue(object, key, newValue);
                                    }
                                }, keysIn);
                            }

                            /**
                             * A specialized version of `baseMerge` for arrays and objects which performs
                             * deep merges and tracks traversed objects enabling objects with circular
                             * references to be merged.
                             *
                             * @private
                             * @param {Object} object The destination object.
                             * @param {Object} source The source object.
                             * @param {string} key The key of the value to merge.
                             * @param {number} srcIndex The index of `source`.
                             * @param {Function} mergeFunc The function to merge values.
                             * @param {Function} [customizer] The function to customize assigned values.
                             * @param {Object} [stack] Tracks traversed source values and their merged
                             *  counterparts.
                             */
                            function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
                                var objValue = safeGet(object, key),
                                    srcValue = safeGet(source, key),
                                    stacked = stack.get(srcValue);

                                if (stacked) {
                                    assignMergeValue(object, key, stacked);
                                    return;
                                }
                                var newValue = customizer
                                    ? customizer(objValue, srcValue, (key + ''), object, source, stack)
                                    : undefined;

                                var isCommon = newValue === undefined;

                                if (isCommon) {
                                    var isArr = isArray(srcValue),
                                        isBuff = !isArr && isBuffer(srcValue),
                                        isTyped = !isArr && !isBuff && isTypedArray(srcValue);

                                    newValue = srcValue;
                                    if (isArr || isBuff || isTyped) {
                                        if (isArray(objValue)) {
                                            newValue = objValue;
                                        }
                                        else if (isArrayLikeObject(objValue)) {
                                            newValue = copyArray(objValue);
                                        }
                                        else if (isBuff) {
                                            isCommon = false;
                                            newValue = cloneBuffer(srcValue, true);
                                        }
                                        else if (isTyped) {
                                            isCommon = false;
                                            newValue = cloneTypedArray(srcValue, true);
                                        }
                                        else {
                                            newValue = [];
                                        }
                                    }
                                    else if (isPlainObject(srcValue) || isArguments(srcValue)) {
                                        newValue = objValue;
                                        if (isArguments(objValue)) {
                                            newValue = toPlainObject(objValue);
                                        }
                                        else if (!isObject(objValue) || isFunction(objValue)) {
                                            newValue = initCloneObject(srcValue);
                                        }
                                    }
                                    else {
                                        isCommon = false;
                                    }
                                }
                                if (isCommon) {
                                    // Recursively merge objects and arrays (susceptible to call stack limits).
                                    stack.set(srcValue, newValue);
                                    mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
                                    stack['delete'](srcValue);
                                }
                                assignMergeValue(object, key, newValue);
                            }

                            /**
                             * The base implementation of `_.nth` which doesn't coerce arguments.
                             *
                             * @private
                             * @param {Array} array The array to query.
                             * @param {number} n The index of the element to return.
                             * @returns {*} Returns the nth element of `array`.
                             */
                            function baseNth(array, n) {
                                var length = array.length;
                                if (!length) {
                                    return;
                                }
                                n += n < 0 ? length : 0;
                                return isIndex(n, length) ? array[n] : undefined;
                            }

                            /**
                             * The base implementation of `_.orderBy` without param guards.
                             *
                             * @private
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
                             * @param {string[]} orders The sort orders of `iteratees`.
                             * @returns {Array} Returns the new sorted array.
                             */
                            function baseOrderBy(collection, iteratees, orders) {
                                if (iteratees.length) {
                                    iteratees = arrayMap(iteratees, function (iteratee) {
                                        if (isArray(iteratee)) {
                                            return function (value) {
                                                return baseGet(value, iteratee.length === 1 ? iteratee[0] : iteratee);
                                            }
                                        }
                                        return iteratee;
                                    });
                                } else {
                                    iteratees = [identity];
                                }

                                var index = -1;
                                iteratees = arrayMap(iteratees, baseUnary(getIteratee()));

                                var result = baseMap(collection, function (value, key, collection) {
                                    var criteria = arrayMap(iteratees, function (iteratee) {
                                        return iteratee(value);
                                    });
                                    return { 'criteria': criteria, 'index': ++index, 'value': value };
                                });

                                return baseSortBy(result, function (object, other) {
                                    return compareMultiple(object, other, orders);
                                });
                            }

                            /**
                             * The base implementation of `_.pick` without support for individual
                             * property identifiers.
                             *
                             * @private
                             * @param {Object} object The source object.
                             * @param {string[]} paths The property paths to pick.
                             * @returns {Object} Returns the new object.
                             */
                            function basePick(object, paths) {
                                return basePickBy(object, paths, function (value, path) {
                                    return hasIn(object, path);
                                });
                            }

                            /**
                             * The base implementation of  `_.pickBy` without support for iteratee shorthands.
                             *
                             * @private
                             * @param {Object} object The source object.
                             * @param {string[]} paths The property paths to pick.
                             * @param {Function} predicate The function invoked per property.
                             * @returns {Object} Returns the new object.
                             */
                            function basePickBy(object, paths, predicate) {
                                var index = -1,
                                    length = paths.length,
                                    result = {};

                                while (++index < length) {
                                    var path = paths[index],
                                        value = baseGet(object, path);

                                    if (predicate(value, path)) {
                                        baseSet(result, castPath(path, object), value);
                                    }
                                }
                                return result;
                            }

                            /**
                             * A specialized version of `baseProperty` which supports deep paths.
                             *
                             * @private
                             * @param {Array|string} path The path of the property to get.
                             * @returns {Function} Returns the new accessor function.
                             */
                            function basePropertyDeep(path) {
                                return function (object) {
                                    return baseGet(object, path);
                                };
                            }

                            /**
                             * The base implementation of `_.pullAllBy` without support for iteratee
                             * shorthands.
                             *
                             * @private
                             * @param {Array} array The array to modify.
                             * @param {Array} values The values to remove.
                             * @param {Function} [iteratee] The iteratee invoked per element.
                             * @param {Function} [comparator] The comparator invoked per element.
                             * @returns {Array} Returns `array`.
                             */
                            function basePullAll(array, values, iteratee, comparator) {
                                var indexOf = comparator ? baseIndexOfWith : baseIndexOf,
                                    index = -1,
                                    length = values.length,
                                    seen = array;

                                if (array === values) {
                                    values = copyArray(values);
                                }
                                if (iteratee) {
                                    seen = arrayMap(array, baseUnary(iteratee));
                                }
                                while (++index < length) {
                                    var fromIndex = 0,
                                        value = values[index],
                                        computed = iteratee ? iteratee(value) : value;

                                    while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
                                        if (seen !== array) {
                                            splice.call(seen, fromIndex, 1);
                                        }
                                        splice.call(array, fromIndex, 1);
                                    }
                                }
                                return array;
                            }

                            /**
                             * The base implementation of `_.pullAt` without support for individual
                             * indexes or capturing the removed elements.
                             *
                             * @private
                             * @param {Array} array The array to modify.
                             * @param {number[]} indexes The indexes of elements to remove.
                             * @returns {Array} Returns `array`.
                             */
                            function basePullAt(array, indexes) {
                                var length = array ? indexes.length : 0,
                                    lastIndex = length - 1;

                                while (length--) {
                                    var index = indexes[length];
                                    if (length == lastIndex || index !== previous) {
                                        var previous = index;
                                        if (isIndex(index)) {
                                            splice.call(array, index, 1);
                                        } else {
                                            baseUnset(array, index);
                                        }
                                    }
                                }
                                return array;
                            }

                            /**
                             * The base implementation of `_.random` without support for returning
                             * floating-point numbers.
                             *
                             * @private
                             * @param {number} lower The lower bound.
                             * @param {number} upper The upper bound.
                             * @returns {number} Returns the random number.
                             */
                            function baseRandom(lower, upper) {
                                return lower + nativeFloor(nativeRandom() * (upper - lower + 1));
                            }

                            /**
                             * The base implementation of `_.range` and `_.rangeRight` which doesn't
                             * coerce arguments.
                             *
                             * @private
                             * @param {number} start The start of the range.
                             * @param {number} end The end of the range.
                             * @param {number} step The value to increment or decrement by.
                             * @param {boolean} [fromRight] Specify iterating from right to left.
                             * @returns {Array} Returns the range of numbers.
                             */
                            function baseRange(start, end, step, fromRight) {
                                var index = -1,
                                    length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
                                    result = Array(length);

                                while (length--) {
                                    result[fromRight ? length : ++index] = start;
                                    start += step;
                                }
                                return result;
                            }

                            /**
                             * The base implementation of `_.repeat` which doesn't coerce arguments.
                             *
                             * @private
                             * @param {string} string The string to repeat.
                             * @param {number} n The number of times to repeat the string.
                             * @returns {string} Returns the repeated string.
                             */
                            function baseRepeat(string, n) {
                                var result = '';
                                if (!string || n < 1 || n > MAX_SAFE_INTEGER) {
                                    return result;
                                }
                                // Leverage the exponentiation by squaring algorithm for a faster repeat.
                                // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details.
                                do {
                                    if (n % 2) {
                                        result += string;
                                    }
                                    n = nativeFloor(n / 2);
                                    if (n) {
                                        string += string;
                                    }
                                } while (n);

                                return result;
                            }

                            /**
                             * The base implementation of `_.rest` which doesn't validate or coerce arguments.
                             *
                             * @private
                             * @param {Function} func The function to apply a rest parameter to.
                             * @param {number} [start=func.length-1] The start position of the rest parameter.
                             * @returns {Function} Returns the new function.
                             */
                            function baseRest(func, start) {
                                return setToString(overRest(func, start, identity), func + '');
                            }

                            /**
                             * The base implementation of `_.sample`.
                             *
                             * @private
                             * @param {Array|Object} collection The collection to sample.
                             * @returns {*} Returns the random element.
                             */
                            function baseSample(collection) {
                                return arraySample(values(collection));
                            }

                            /**
                             * The base implementation of `_.sampleSize` without param guards.
                             *
                             * @private
                             * @param {Array|Object} collection The collection to sample.
                             * @param {number} n The number of elements to sample.
                             * @returns {Array} Returns the random elements.
                             */
                            function baseSampleSize(collection, n) {
                                var array = values(collection);
                                return shuffleSelf(array, baseClamp(n, 0, array.length));
                            }

                            /**
                             * The base implementation of `_.set`.
                             *
                             * @private
                             * @param {Object} object The object to modify.
                             * @param {Array|string} path The path of the property to set.
                             * @param {*} value The value to set.
                             * @param {Function} [customizer] The function to customize path creation.
                             * @returns {Object} Returns `object`.
                             */
                            function baseSet(object, path, value, customizer) {
                                if (!isObject(object)) {
                                    return object;
                                }
                                path = castPath(path, object);

                                var index = -1,
                                    length = path.length,
                                    lastIndex = length - 1,
                                    nested = object;

                                while (nested != null && ++index < length) {
                                    var key = toKey(path[index]),
                                        newValue = value;

                                    if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
                                        return object;
                                    }

                                    if (index != lastIndex) {
                                        var objValue = nested[key];
                                        newValue = customizer ? customizer(objValue, key, nested) : undefined;
                                        if (newValue === undefined) {
                                            newValue = isObject(objValue)
                                                ? objValue
                                                : (isIndex(path[index + 1]) ? [] : {});
                                        }
                                    }
                                    assignValue(nested, key, newValue);
                                    nested = nested[key];
                                }
                                return object;
                            }

                            /**
                             * The base implementation of `setData` without support for hot loop shorting.
                             *
                             * @private
                             * @param {Function} func The function to associate metadata with.
                             * @param {*} data The metadata.
                             * @returns {Function} Returns `func`.
                             */
                            var baseSetData = !metaMap ? identity : function (func, data) {
                                metaMap.set(func, data);
                                return func;
                            };

                            /**
                             * The base implementation of `setToString` without support for hot loop shorting.
                             *
                             * @private
                             * @param {Function} func The function to modify.
                             * @param {Function} string The `toString` result.
                             * @returns {Function} Returns `func`.
                             */
                            var baseSetToString = !defineProperty ? identity : function (func, string) {
                                return defineProperty(func, 'toString', {
                                    'configurable': true,
                                    'enumerable': false,
                                    'value': constant(string),
                                    'writable': true
                                });
                            };

                            /**
                             * The base implementation of `_.shuffle`.
                             *
                             * @private
                             * @param {Array|Object} collection The collection to shuffle.
                             * @returns {Array} Returns the new shuffled array.
                             */
                            function baseShuffle(collection) {
                                return shuffleSelf(values(collection));
                            }

                            /**
                             * The base implementation of `_.slice` without an iteratee call guard.
                             *
                             * @private
                             * @param {Array} array The array to slice.
                             * @param {number} [start=0] The start position.
                             * @param {number} [end=array.length] The end position.
                             * @returns {Array} Returns the slice of `array`.
                             */
                            function baseSlice(array, start, end) {
                                var index = -1,
                                    length = array.length;

                                if (start < 0) {
                                    start = -start > length ? 0 : (length + start);
                                }
                                end = end > length ? length : end;
                                if (end < 0) {
                                    end += length;
                                }
                                length = start > end ? 0 : ((end - start) >>> 0);
                                start >>>= 0;

                                var result = Array(length);
                                while (++index < length) {
                                    result[index] = array[index + start];
                                }
                                return result;
                            }

                            /**
                             * The base implementation of `_.some` without support for iteratee shorthands.
                             *
                             * @private
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} predicate The function invoked per iteration.
                             * @returns {boolean} Returns `true` if any element passes the predicate check,
                             *  else `false`.
                             */
                            function baseSome(collection, predicate) {
                                var result;

                                baseEach(collection, function (value, index, collection) {
                                    result = predicate(value, index, collection);
                                    return !result;
                                });
                                return !!result;
                            }

                            /**
                             * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which
                             * performs a binary search of `array` to determine the index at which `value`
                             * should be inserted into `array` in order to maintain its sort order.
                             *
                             * @private
                             * @param {Array} array The sorted array to inspect.
                             * @param {*} value The value to evaluate.
                             * @param {boolean} [retHighest] Specify returning the highest qualified index.
                             * @returns {number} Returns the index at which `value` should be inserted
                             *  into `array`.
                             */
                            function baseSortedIndex(array, value, retHighest) {
                                var low = 0,
                                    high = array == null ? low : array.length;

                                if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
                                    while (low < high) {
                                        var mid = (low + high) >>> 1,
                                            computed = array[mid];

                                        if (computed !== null && !isSymbol(computed) &&
                                            (retHighest ? (computed <= value) : (computed < value))) {
                                            low = mid + 1;
                                        } else {
                                            high = mid;
                                        }
                                    }
                                    return high;
                                }
                                return baseSortedIndexBy(array, value, identity, retHighest);
                            }

                            /**
                             * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy`
                             * which invokes `iteratee` for `value` and each element of `array` to compute
                             * their sort ranking. The iteratee is invoked with one argument; (value).
                             *
                             * @private
                             * @param {Array} array The sorted array to inspect.
                             * @param {*} value The value to evaluate.
                             * @param {Function} iteratee The iteratee invoked per element.
                             * @param {boolean} [retHighest] Specify returning the highest qualified index.
                             * @returns {number} Returns the index at which `value` should be inserted
                             *  into `array`.
                             */
                            function baseSortedIndexBy(array, value, iteratee, retHighest) {
                                var low = 0,
                                    high = array == null ? 0 : array.length;
                                if (high === 0) {
                                    return 0;
                                }

                                value = iteratee(value);
                                var valIsNaN = value !== value,
                                    valIsNull = value === null,
                                    valIsSymbol = isSymbol(value),
                                    valIsUndefined = value === undefined;

                                while (low < high) {
                                    var mid = nativeFloor((low + high) / 2),
                                        computed = iteratee(array[mid]),
                                        othIsDefined = computed !== undefined,
                                        othIsNull = computed === null,
                                        othIsReflexive = computed === computed,
                                        othIsSymbol = isSymbol(computed);

                                    if (valIsNaN) {
                                        var setLow = retHighest || othIsReflexive;
                                    } else if (valIsUndefined) {
                                        setLow = othIsReflexive && (retHighest || othIsDefined);
                                    } else if (valIsNull) {
                                        setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);
                                    } else if (valIsSymbol) {
                                        setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);
                                    } else if (othIsNull || othIsSymbol) {
                                        setLow = false;
                                    } else {
                                        setLow = retHighest ? (computed <= value) : (computed < value);
                                    }
                                    if (setLow) {
                                        low = mid + 1;
                                    } else {
                                        high = mid;
                                    }
                                }
                                return nativeMin(high, MAX_ARRAY_INDEX);
                            }

                            /**
                             * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without
                             * support for iteratee shorthands.
                             *
                             * @private
                             * @param {Array} array The array to inspect.
                             * @param {Function} [iteratee] The iteratee invoked per element.
                             * @returns {Array} Returns the new duplicate free array.
                             */
                            function baseSortedUniq(array, iteratee) {
                                var index = -1,
                                    length = array.length,
                                    resIndex = 0,
                                    result = [];

                                while (++index < length) {
                                    var value = array[index],
                                        computed = iteratee ? iteratee(value) : value;

                                    if (!index || !eq(computed, seen)) {
                                        var seen = computed;
                                        result[resIndex++] = value === 0 ? 0 : value;
                                    }
                                }
                                return result;
                            }

                            /**
                             * The base implementation of `_.toNumber` which doesn't ensure correct
                             * conversions of binary, hexadecimal, or octal string values.
                             *
                             * @private
                             * @param {*} value The value to process.
                             * @returns {number} Returns the number.
                             */
                            function baseToNumber(value) {
                                if (typeof value == 'number') {
                                    return value;
                                }
                                if (isSymbol(value)) {
                                    return NAN;
                                }
                                return +value;
                            }

                            /**
                             * The base implementation of `_.toString` which doesn't convert nullish
                             * values to empty strings.
                             *
                             * @private
                             * @param {*} value The value to process.
                             * @returns {string} Returns the string.
                             */
                            function baseToString(value) {
                                // Exit early for strings to avoid a performance hit in some environments.
                                if (typeof value == 'string') {
                                    return value;
                                }
                                if (isArray(value)) {
                                    // Recursively convert values (susceptible to call stack limits).
                                    return arrayMap(value, baseToString) + '';
                                }
                                if (isSymbol(value)) {
                                    return symbolToString ? symbolToString.call(value) : '';
                                }
                                var result = (value + '');
                                return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
                            }

                            /**
                             * The base implementation of `_.uniqBy` without support for iteratee shorthands.
                             *
                             * @private
                             * @param {Array} array The array to inspect.
                             * @param {Function} [iteratee] The iteratee invoked per element.
                             * @param {Function} [comparator] The comparator invoked per element.
                             * @returns {Array} Returns the new duplicate free array.
                             */
                            function baseUniq(array, iteratee, comparator) {
                                var index = -1,
                                    includes = arrayIncludes,
                                    length = array.length,
                                    isCommon = true,
                                    result = [],
                                    seen = result;

                                if (comparator) {
                                    isCommon = false;
                                    includes = arrayIncludesWith;
                                }
                                else if (length >= LARGE_ARRAY_SIZE) {
                                    var set = iteratee ? null : createSet(array);
                                    if (set) {
                                        return setToArray(set);
                                    }
                                    isCommon = false;
                                    includes = cacheHas;
                                    seen = new SetCache;
                                }
                                else {
                                    seen = iteratee ? [] : result;
                                }
                                outer:
                                while (++index < length) {
                                    var value = array[index],
                                        computed = iteratee ? iteratee(value) : value;

                                    value = (comparator || value !== 0) ? value : 0;
                                    if (isCommon && computed === computed) {
                                        var seenIndex = seen.length;
                                        while (seenIndex--) {
                                            if (seen[seenIndex] === computed) {
                                                continue outer;
                                            }
                                        }
                                        if (iteratee) {
                                            seen.push(computed);
                                        }
                                        result.push(value);
                                    }
                                    else if (!includes(seen, computed, comparator)) {
                                        if (seen !== result) {
                                            seen.push(computed);
                                        }
                                        result.push(value);
                                    }
                                }
                                return result;
                            }

                            /**
                             * The base implementation of `_.unset`.
                             *
                             * @private
                             * @param {Object} object The object to modify.
                             * @param {Array|string} path The property path to unset.
                             * @returns {boolean} Returns `true` if the property is deleted, else `false`.
                             */
                            function baseUnset(object, path) {
                                path = castPath(path, object);
                                object = parent(object, path);
                                return object == null || delete object[toKey(last(path))];
                            }

                            /**
                             * The base implementation of `_.update`.
                             *
                             * @private
                             * @param {Object} object The object to modify.
                             * @param {Array|string} path The path of the property to update.
                             * @param {Function} updater The function to produce the updated value.
                             * @param {Function} [customizer] The function to customize path creation.
                             * @returns {Object} Returns `object`.
                             */
                            function baseUpdate(object, path, updater, customizer) {
                                return baseSet(object, path, updater(baseGet(object, path)), customizer);
                            }

                            /**
                             * The base implementation of methods like `_.dropWhile` and `_.takeWhile`
                             * without support for iteratee shorthands.
                             *
                             * @private
                             * @param {Array} array The array to query.
                             * @param {Function} predicate The function invoked per iteration.
                             * @param {boolean} [isDrop] Specify dropping elements instead of taking them.
                             * @param {boolean} [fromRight] Specify iterating from right to left.
                             * @returns {Array} Returns the slice of `array`.
                             */
                            function baseWhile(array, predicate, isDrop, fromRight) {
                                var length = array.length,
                                    index = fromRight ? length : -1;

                                while ((fromRight ? index-- : ++index < length) &&
                                    predicate(array[index], index, array)) { }

                                return isDrop
                                    ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))
                                    : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index));
                            }

                            /**
                             * The base implementation of `wrapperValue` which returns the result of
                             * performing a sequence of actions on the unwrapped `value`, where each
                             * successive action is supplied the return value of the previous.
                             *
                             * @private
                             * @param {*} value The unwrapped value.
                             * @param {Array} actions Actions to perform to resolve the unwrapped value.
                             * @returns {*} Returns the resolved value.
                             */
                            function baseWrapperValue(value, actions) {
                                var result = value;
                                if (result instanceof LazyWrapper) {
                                    result = result.value();
                                }
                                return arrayReduce(actions, function (result, action) {
                                    return action.func.apply(action.thisArg, arrayPush([result], action.args));
                                }, result);
                            }

                            /**
                             * The base implementation of methods like `_.xor`, without support for
                             * iteratee shorthands, that accepts an array of arrays to inspect.
                             *
                             * @private
                             * @param {Array} arrays The arrays to inspect.
                             * @param {Function} [iteratee] The iteratee invoked per element.
                             * @param {Function} [comparator] The comparator invoked per element.
                             * @returns {Array} Returns the new array of values.
                             */
                            function baseXor(arrays, iteratee, comparator) {
                                var length = arrays.length;
                                if (length < 2) {
                                    return length ? baseUniq(arrays[0]) : [];
                                }
                                var index = -1,
                                    result = Array(length);

                                while (++index < length) {
                                    var array = arrays[index],
                                        othIndex = -1;

                                    while (++othIndex < length) {
                                        if (othIndex != index) {
                                            result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator);
                                        }
                                    }
                                }
                                return baseUniq(baseFlatten(result, 1), iteratee, comparator);
                            }

                            /**
                             * This base implementation of `_.zipObject` which assigns values using `assignFunc`.
                             *
                             * @private
                             * @param {Array} props The property identifiers.
                             * @param {Array} values The property values.
                             * @param {Function} assignFunc The function to assign values.
                             * @returns {Object} Returns the new object.
                             */
                            function baseZipObject(props, values, assignFunc) {
                                var index = -1,
                                    length = props.length,
                                    valsLength = values.length,
                                    result = {};

                                while (++index < length) {
                                    var value = index < valsLength ? values[index] : undefined;
                                    assignFunc(result, props[index], value);
                                }
                                return result;
                            }

                            /**
                             * Casts `value` to an empty array if it's not an array like object.
                             *
                             * @private
                             * @param {*} value The value to inspect.
                             * @returns {Array|Object} Returns the cast array-like object.
                             */
                            function castArrayLikeObject(value) {
                                return isArrayLikeObject(value) ? value : [];
                            }

                            /**
                             * Casts `value` to `identity` if it's not a function.
                             *
                             * @private
                             * @param {*} value The value to inspect.
                             * @returns {Function} Returns cast function.
                             */
                            function castFunction(value) {
                                return typeof value == 'function' ? value : identity;
                            }

                            /**
                             * Casts `value` to a path array if it's not one.
                             *
                             * @private
                             * @param {*} value The value to inspect.
                             * @param {Object} [object] The object to query keys on.
                             * @returns {Array} Returns the cast property path array.
                             */
                            function castPath(value, object) {
                                if (isArray(value)) {
                                    return value;
                                }
                                return isKey(value, object) ? [value] : stringToPath(toString(value));
                            }

                            /**
                             * A `baseRest` alias which can be replaced with `identity` by module
                             * replacement plugins.
                             *
                             * @private
                             * @type {Function}
                             * @param {Function} func The function to apply a rest parameter to.
                             * @returns {Function} Returns the new function.
                             */
                            var castRest = baseRest;

                            /**
                             * Casts `array` to a slice if it's needed.
                             *
                             * @private
                             * @param {Array} array The array to inspect.
                             * @param {number} start The start position.
                             * @param {number} [end=array.length] The end position.
                             * @returns {Array} Returns the cast slice.
                             */
                            function castSlice(array, start, end) {
                                var length = array.length;
                                end = end === undefined ? length : end;
                                return (!start && end >= length) ? array : baseSlice(array, start, end);
                            }

                            /**
                             * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout).
                             *
                             * @private
                             * @param {number|Object} id The timer id or timeout object of the timer to clear.
                             */
                            var clearTimeout = ctxClearTimeout || function (id) {
                                return root.clearTimeout(id);
                            };

                            /**
                             * Creates a clone of  `buffer`.
                             *
                             * @private
                             * @param {Buffer} buffer The buffer to clone.
                             * @param {boolean} [isDeep] Specify a deep clone.
                             * @returns {Buffer} Returns the cloned buffer.
                             */
                            function cloneBuffer(buffer, isDeep) {
                                if (isDeep) {
                                    return buffer.slice();
                                }
                                var length = buffer.length,
                                    result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);

                                buffer.copy(result);
                                return result;
                            }

                            /**
                             * Creates a clone of `arrayBuffer`.
                             *
                             * @private
                             * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
                             * @returns {ArrayBuffer} Returns the cloned array buffer.
                             */
                            function cloneArrayBuffer(arrayBuffer) {
                                var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
                                new Uint8Array(result).set(new Uint8Array(arrayBuffer));
                                return result;
                            }

                            /**
                             * Creates a clone of `dataView`.
                             *
                             * @private
                             * @param {Object} dataView The data view to clone.
                             * @param {boolean} [isDeep] Specify a deep clone.
                             * @returns {Object} Returns the cloned data view.
                             */
                            function cloneDataView(dataView, isDeep) {
                                var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
                                return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
                            }

                            /**
                             * Creates a clone of `regexp`.
                             *
                             * @private
                             * @param {Object} regexp The regexp to clone.
                             * @returns {Object} Returns the cloned regexp.
                             */
                            function cloneRegExp(regexp) {
                                var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
                                result.lastIndex = regexp.lastIndex;
                                return result;
                            }

                            /**
                             * Creates a clone of the `symbol` object.
                             *
                             * @private
                             * @param {Object} symbol The symbol object to clone.
                             * @returns {Object} Returns the cloned symbol object.
                             */
                            function cloneSymbol(symbol) {
                                return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
                            }

                            /**
                             * Creates a clone of `typedArray`.
                             *
                             * @private
                             * @param {Object} typedArray The typed array to clone.
                             * @param {boolean} [isDeep] Specify a deep clone.
                             * @returns {Object} Returns the cloned typed array.
                             */
                            function cloneTypedArray(typedArray, isDeep) {
                                var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
                                return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
                            }

                            /**
                             * Compares values to sort them in ascending order.
                             *
                             * @private
                             * @param {*} value The value to compare.
                             * @param {*} other The other value to compare.
                             * @returns {number} Returns the sort order indicator for `value`.
                             */
                            function compareAscending(value, other) {
                                if (value !== other) {
                                    var valIsDefined = value !== undefined,
                                        valIsNull = value === null,
                                        valIsReflexive = value === value,
                                        valIsSymbol = isSymbol(value);

                                    var othIsDefined = other !== undefined,
                                        othIsNull = other === null,
                                        othIsReflexive = other === other,
                                        othIsSymbol = isSymbol(other);

                                    if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) ||
                                        (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||
                                        (valIsNull && othIsDefined && othIsReflexive) ||
                                        (!valIsDefined && othIsReflexive) ||
                                        !valIsReflexive) {
                                        return 1;
                                    }
                                    if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) ||
                                        (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||
                                        (othIsNull && valIsDefined && valIsReflexive) ||
                                        (!othIsDefined && valIsReflexive) ||
                                        !othIsReflexive) {
                                        return -1;
                                    }
                                }
                                return 0;
                            }

                            /**
                             * Used by `_.orderBy` to compare multiple properties of a value to another
                             * and stable sort them.
                             *
                             * If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
                             * specify an order of "desc" for descending or "asc" for ascending sort order
                             * of corresponding values.
                             *
                             * @private
                             * @param {Object} object The object to compare.
                             * @param {Object} other The other object to compare.
                             * @param {boolean[]|string[]} orders The order to sort by for each property.
                             * @returns {number} Returns the sort order indicator for `object`.
                             */
                            function compareMultiple(object, other, orders) {
                                var index = -1,
                                    objCriteria = object.criteria,
                                    othCriteria = other.criteria,
                                    length = objCriteria.length,
                                    ordersLength = orders.length;

                                while (++index < length) {
                                    var result = compareAscending(objCriteria[index], othCriteria[index]);
                                    if (result) {
                                        if (index >= ordersLength) {
                                            return result;
                                        }
                                        var order = orders[index];
                                        return result * (order == 'desc' ? -1 : 1);
                                    }
                                }
                                // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
                                // that causes it, under certain circumstances, to provide the same value for
                                // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
                                // for more details.
                                //
                                // This also ensures a stable sort in V8 and other engines.
                                // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
                                return object.index - other.index;
                            }

                            /**
                             * Creates an array that is the composition of partially applied arguments,
                             * placeholders, and provided arguments into a single array of arguments.
                             *
                             * @private
                             * @param {Array} args The provided arguments.
                             * @param {Array} partials The arguments to prepend to those provided.
                             * @param {Array} holders The `partials` placeholder indexes.
                             * @params {boolean} [isCurried] Specify composing for a curried function.
                             * @returns {Array} Returns the new array of composed arguments.
                             */
                            function composeArgs(args, partials, holders, isCurried) {
                                var argsIndex = -1,
                                    argsLength = args.length,
                                    holdersLength = holders.length,
                                    leftIndex = -1,
                                    leftLength = partials.length,
                                    rangeLength = nativeMax(argsLength - holdersLength, 0),
                                    result = Array(leftLength + rangeLength),
                                    isUncurried = !isCurried;

                                while (++leftIndex < leftLength) {
                                    result[leftIndex] = partials[leftIndex];
                                }
                                while (++argsIndex < holdersLength) {
                                    if (isUncurried || argsIndex < argsLength) {
                                        result[holders[argsIndex]] = args[argsIndex];
                                    }
                                }
                                while (rangeLength--) {
                                    result[leftIndex++] = args[argsIndex++];
                                }
                                return result;
                            }

                            /**
                             * This function is like `composeArgs` except that the arguments composition
                             * is tailored for `_.partialRight`.
                             *
                             * @private
                             * @param {Array} args The provided arguments.
                             * @param {Array} partials The arguments to append to those provided.
                             * @param {Array} holders The `partials` placeholder indexes.
                             * @params {boolean} [isCurried] Specify composing for a curried function.
                             * @returns {Array} Returns the new array of composed arguments.
                             */
                            function composeArgsRight(args, partials, holders, isCurried) {
                                var argsIndex = -1,
                                    argsLength = args.length,
                                    holdersIndex = -1,
                                    holdersLength = holders.length,
                                    rightIndex = -1,
                                    rightLength = partials.length,
                                    rangeLength = nativeMax(argsLength - holdersLength, 0),
                                    result = Array(rangeLength + rightLength),
                                    isUncurried = !isCurried;

                                while (++argsIndex < rangeLength) {
                                    result[argsIndex] = args[argsIndex];
                                }
                                var offset = argsIndex;
                                while (++rightIndex < rightLength) {
                                    result[offset + rightIndex] = partials[rightIndex];
                                }
                                while (++holdersIndex < holdersLength) {
                                    if (isUncurried || argsIndex < argsLength) {
                                        result[offset + holders[holdersIndex]] = args[argsIndex++];
                                    }
                                }
                                return result;
                            }

                            /**
                             * Copies the values of `source` to `array`.
                             *
                             * @private
                             * @param {Array} source The array to copy values from.
                             * @param {Array} [array=[]] The array to copy values to.
                             * @returns {Array} Returns `array`.
                             */
                            function copyArray(source, array) {
                                var index = -1,
                                    length = source.length;

                                array || (array = Array(length));
                                while (++index < length) {
                                    array[index] = source[index];
                                }
                                return array;
                            }

                            /**
                             * Copies properties of `source` to `object`.
                             *
                             * @private
                             * @param {Object} source The object to copy properties from.
                             * @param {Array} props The property identifiers to copy.
                             * @param {Object} [object={}] The object to copy properties to.
                             * @param {Function} [customizer] The function to customize copied values.
                             * @returns {Object} Returns `object`.
                             */
                            function copyObject(source, props, object, customizer) {
                                var isNew = !object;
                                object || (object = {});

                                var index = -1,
                                    length = props.length;

                                while (++index < length) {
                                    var key = props[index];

                                    var newValue = customizer
                                        ? customizer(object[key], source[key], key, object, source)
                                        : undefined;

                                    if (newValue === undefined) {
                                        newValue = source[key];
                                    }
                                    if (isNew) {
                                        baseAssignValue(object, key, newValue);
                                    } else {
                                        assignValue(object, key, newValue);
                                    }
                                }
                                return object;
                            }

                            /**
                             * Copies own symbols of `source` to `object`.
                             *
                             * @private
                             * @param {Object} source The object to copy symbols from.
                             * @param {Object} [object={}] The object to copy symbols to.
                             * @returns {Object} Returns `object`.
                             */
                            function copySymbols(source, object) {
                                return copyObject(source, getSymbols(source), object);
                            }

                            /**
                             * Copies own and inherited symbols of `source` to `object`.
                             *
                             * @private
                             * @param {Object} source The object to copy symbols from.
                             * @param {Object} [object={}] The object to copy symbols to.
                             * @returns {Object} Returns `object`.
                             */
                            function copySymbolsIn(source, object) {
                                return copyObject(source, getSymbolsIn(source), object);
                            }

                            /**
                             * Creates a function like `_.groupBy`.
                             *
                             * @private
                             * @param {Function} setter The function to set accumulator values.
                             * @param {Function} [initializer] The accumulator object initializer.
                             * @returns {Function} Returns the new aggregator function.
                             */
                            function createAggregator(setter, initializer) {
                                return function (collection, iteratee) {
                                    var func = isArray(collection) ? arrayAggregator : baseAggregator,
                                        accumulator = initializer ? initializer() : {};

                                    return func(collection, setter, getIteratee(iteratee, 2), accumulator);
                                };
                            }

                            /**
                             * Creates a function like `_.assign`.
                             *
                             * @private
                             * @param {Function} assigner The function to assign values.
                             * @returns {Function} Returns the new assigner function.
                             */
                            function createAssigner(assigner) {
                                return baseRest(function (object, sources) {
                                    var index = -1,
                                        length = sources.length,
                                        customizer = length > 1 ? sources[length - 1] : undefined,
                                        guard = length > 2 ? sources[2] : undefined;

                                    customizer = (assigner.length > 3 && typeof customizer == 'function')
                                        ? (length--, customizer)
                                        : undefined;

                                    if (guard && isIterateeCall(sources[0], sources[1], guard)) {
                                        customizer = length < 3 ? undefined : customizer;
                                        length = 1;
                                    }
                                    object = Object(object);
                                    while (++index < length) {
                                        var source = sources[index];
                                        if (source) {
                                            assigner(object, source, index, customizer);
                                        }
                                    }
                                    return object;
                                });
                            }

                            /**
                             * Creates a `baseEach` or `baseEachRight` function.
                             *
                             * @private
                             * @param {Function} eachFunc The function to iterate over a collection.
                             * @param {boolean} [fromRight] Specify iterating from right to left.
                             * @returns {Function} Returns the new base function.
                             */
                            function createBaseEach(eachFunc, fromRight) {
                                return function (collection, iteratee) {
                                    if (collection == null) {
                                        return collection;
                                    }
                                    if (!isArrayLike(collection)) {
                                        return eachFunc(collection, iteratee);
                                    }
                                    var length = collection.length,
                                        index = fromRight ? length : -1,
                                        iterable = Object(collection);

                                    while ((fromRight ? index-- : ++index < length)) {
                                        if (iteratee(iterable[index], index, iterable) === false) {
                                            break;
                                        }
                                    }
                                    return collection;
                                };
                            }

                            /**
                             * Creates a base function for methods like `_.forIn` and `_.forOwn`.
                             *
                             * @private
                             * @param {boolean} [fromRight] Specify iterating from right to left.
                             * @returns {Function} Returns the new base function.
                             */
                            function createBaseFor(fromRight) {
                                return function (object, iteratee, keysFunc) {
                                    var index = -1,
                                        iterable = Object(object),
                                        props = keysFunc(object),
                                        length = props.length;

                                    while (length--) {
                                        var key = props[fromRight ? length : ++index];
                                        if (iteratee(iterable[key], key, iterable) === false) {
                                            break;
                                        }
                                    }
                                    return object;
                                };
                            }

                            /**
                             * Creates a function that wraps `func` to invoke it with the optional `this`
                             * binding of `thisArg`.
                             *
                             * @private
                             * @param {Function} func The function to wrap.
                             * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
                             * @param {*} [thisArg] The `this` binding of `func`.
                             * @returns {Function} Returns the new wrapped function.
                             */
                            function createBind(func, bitmask, thisArg) {
                                var isBind = bitmask & WRAP_BIND_FLAG,
                                    Ctor = createCtor(func);

                                function wrapper() {
                                    var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
                                    return fn.apply(isBind ? thisArg : this, arguments);
                                }
                                return wrapper;
                            }

                            /**
                             * Creates a function like `_.lowerFirst`.
                             *
                             * @private
                             * @param {string} methodName The name of the `String` case method to use.
                             * @returns {Function} Returns the new case function.
                             */
                            function createCaseFirst(methodName) {
                                return function (string) {
                                    string = toString(string);

                                    var strSymbols = hasUnicode(string)
                                        ? stringToArray(string)
                                        : undefined;

                                    var chr = strSymbols
                                        ? strSymbols[0]
                                        : string.charAt(0);

                                    var trailing = strSymbols
                                        ? castSlice(strSymbols, 1).join('')
                                        : string.slice(1);

                                    return chr[methodName]() + trailing;
                                };
                            }

                            /**
                             * Creates a function like `_.camelCase`.
                             *
                             * @private
                             * @param {Function} callback The function to combine each word.
                             * @returns {Function} Returns the new compounder function.
                             */
                            function createCompounder(callback) {
                                return function (string) {
                                    return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
                                };
                            }

                            /**
                             * Creates a function that produces an instance of `Ctor` regardless of
                             * whether it was invoked as part of a `new` expression or by `call` or `apply`.
                             *
                             * @private
                             * @param {Function} Ctor The constructor to wrap.
                             * @returns {Function} Returns the new wrapped function.
                             */
                            function createCtor(Ctor) {
                                return function () {
                                    // Use a `switch` statement to work with class constructors. See
                                    // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
                                    // for more details.
                                    var args = arguments;
                                    switch (args.length) {
                                        case 0: return new Ctor;
                                        case 1: return new Ctor(args[0]);
                                        case 2: return new Ctor(args[0], args[1]);
                                        case 3: return new Ctor(args[0], args[1], args[2]);
                                        case 4: return new Ctor(args[0], args[1], args[2], args[3]);
                                        case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
                                        case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
                                        case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
                                    }
                                    var thisBinding = baseCreate(Ctor.prototype),
                                        result = Ctor.apply(thisBinding, args);

                                    // Mimic the constructor's `return` behavior.
                                    // See https://es5.github.io/#x13.2.2 for more details.
                                    return isObject(result) ? result : thisBinding;
                                };
                            }

                            /**
                             * Creates a function that wraps `func` to enable currying.
                             *
                             * @private
                             * @param {Function} func The function to wrap.
                             * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
                             * @param {number} arity The arity of `func`.
                             * @returns {Function} Returns the new wrapped function.
                             */
                            function createCurry(func, bitmask, arity) {
                                var Ctor = createCtor(func);

                                function wrapper() {
                                    var length = arguments.length,
                                        args = Array(length),
                                        index = length,
                                        placeholder = getHolder(wrapper);

                                    while (index--) {
                                        args[index] = arguments[index];
                                    }
                                    var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder)
                                        ? []
                                        : replaceHolders(args, placeholder);

                                    length -= holders.length;
                                    if (length < arity) {
                                        return createRecurry(
                                            func, bitmask, createHybrid, wrapper.placeholder, undefined,
                                            args, holders, undefined, undefined, arity - length);
                                    }
                                    var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
                                    return apply(fn, this, args);
                                }
                                return wrapper;
                            }

                            /**
                             * Creates a `_.find` or `_.findLast` function.
                             *
                             * @private
                             * @param {Function} findIndexFunc The function to find the collection index.
                             * @returns {Function} Returns the new find function.
                             */
                            function createFind(findIndexFunc) {
                                return function (collection, predicate, fromIndex) {
                                    var iterable = Object(collection);
                                    if (!isArrayLike(collection)) {
                                        var iteratee = getIteratee(predicate, 3);
                                        collection = keys(collection);
                                        predicate = function (key) { return iteratee(iterable[key], key, iterable); };
                                    }
                                    var index = findIndexFunc(collection, predicate, fromIndex);
                                    return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;
                                };
                            }

                            /**
                             * Creates a `_.flow` or `_.flowRight` function.
                             *
                             * @private
                             * @param {boolean} [fromRight] Specify iterating from right to left.
                             * @returns {Function} Returns the new flow function.
                             */
                            function createFlow(fromRight) {
                                return flatRest(function (funcs) {
                                    var length = funcs.length,
                                        index = length,
                                        prereq = LodashWrapper.prototype.thru;

                                    if (fromRight) {
                                        funcs.reverse();
                                    }
                                    while (index--) {
                                        var func = funcs[index];
                                        if (typeof func != 'function') {
                                            throw new TypeError(FUNC_ERROR_TEXT);
                                        }
                                        if (prereq && !wrapper && getFuncName(func) == 'wrapper') {
                                            var wrapper = new LodashWrapper([], true);
                                        }
                                    }
                                    index = wrapper ? index : length;
                                    while (++index < length) {
                                        func = funcs[index];

                                        var funcName = getFuncName(func),
                                            data = funcName == 'wrapper' ? getData(func) : undefined;

                                        if (data && isLaziable(data[0]) &&
                                            data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) &&
                                            !data[4].length && data[9] == 1
                                        ) {
                                            wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]);
                                        } else {
                                            wrapper = (func.length == 1 && isLaziable(func))
                                                ? wrapper[funcName]()
                                                : wrapper.thru(func);
                                        }
                                    }
                                    return function () {
                                        var args = arguments,
                                            value = args[0];

                                        if (wrapper && args.length == 1 && isArray(value)) {
                                            return wrapper.plant(value).value();
                                        }
                                        var index = 0,
                                            result = length ? funcs[index].apply(this, args) : value;

                                        while (++index < length) {
                                            result = funcs[index].call(this, result);
                                        }
                                        return result;
                                    };
                                });
                            }

                            /**
                             * Creates a function that wraps `func` to invoke it with optional `this`
                             * binding of `thisArg`, partial application, and currying.
                             *
                             * @private
                             * @param {Function|string} func The function or method name to wrap.
                             * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
                             * @param {*} [thisArg] The `this` binding of `func`.
                             * @param {Array} [partials] The arguments to prepend to those provided to
                             *  the new function.
                             * @param {Array} [holders] The `partials` placeholder indexes.
                             * @param {Array} [partialsRight] The arguments to append to those provided
                             *  to the new function.
                             * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
                             * @param {Array} [argPos] The argument positions of the new function.
                             * @param {number} [ary] The arity cap of `func`.
                             * @param {number} [arity] The arity of `func`.
                             * @returns {Function} Returns the new wrapped function.
                             */
                            function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
                                var isAry = bitmask & WRAP_ARY_FLAG,
                                    isBind = bitmask & WRAP_BIND_FLAG,
                                    isBindKey = bitmask & WRAP_BIND_KEY_FLAG,
                                    isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG),
                                    isFlip = bitmask & WRAP_FLIP_FLAG,
                                    Ctor = isBindKey ? undefined : createCtor(func);

                                function wrapper() {
                                    var length = arguments.length,
                                        args = Array(length),
                                        index = length;

                                    while (index--) {
                                        args[index] = arguments[index];
                                    }
                                    if (isCurried) {
                                        var placeholder = getHolder(wrapper),
                                            holdersCount = countHolders(args, placeholder);
                                    }
                                    if (partials) {
                                        args = composeArgs(args, partials, holders, isCurried);
                                    }
                                    if (partialsRight) {
                                        args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
                                    }
                                    length -= holdersCount;
                                    if (isCurried && length < arity) {
                                        var newHolders = replaceHolders(args, placeholder);
                                        return createRecurry(
                                            func, bitmask, createHybrid, wrapper.placeholder, thisArg,
                                            args, newHolders, argPos, ary, arity - length
                                        );
                                    }
                                    var thisBinding = isBind ? thisArg : this,
                                        fn = isBindKey ? thisBinding[func] : func;

                                    length = args.length;
                                    if (argPos) {
                                        args = reorder(args, argPos);
                                    } else if (isFlip && length > 1) {
                                        args.reverse();
                                    }
                                    if (isAry && ary < length) {
                                        args.length = ary;
                                    }
                                    if (this && this !== root && this instanceof wrapper) {
                                        fn = Ctor || createCtor(fn);
                                    }
                                    return fn.apply(thisBinding, args);
                                }
                                return wrapper;
                            }

                            /**
                             * Creates a function like `_.invertBy`.
                             *
                             * @private
                             * @param {Function} setter The function to set accumulator values.
                             * @param {Function} toIteratee The function to resolve iteratees.
                             * @returns {Function} Returns the new inverter function.
                             */
                            function createInverter(setter, toIteratee) {
                                return function (object, iteratee) {
                                    return baseInverter(object, setter, toIteratee(iteratee), {});
                                };
                            }

                            /**
                             * Creates a function that performs a mathematical operation on two values.
                             *
                             * @private
                             * @param {Function} operator The function to perform the operation.
                             * @param {number} [defaultValue] The value used for `undefined` arguments.
                             * @returns {Function} Returns the new mathematical operation function.
                             */
                            function createMathOperation(operator, defaultValue) {
                                return function (value, other) {
                                    var result;
                                    if (value === undefined && other === undefined) {
                                        return defaultValue;
                                    }
                                    if (value !== undefined) {
                                        result = value;
                                    }
                                    if (other !== undefined) {
                                        if (result === undefined) {
                                            return other;
                                        }
                                        if (typeof value == 'string' || typeof other == 'string') {
                                            value = baseToString(value);
                                            other = baseToString(other);
                                        } else {
                                            value = baseToNumber(value);
                                            other = baseToNumber(other);
                                        }
                                        result = operator(value, other);
                                    }
                                    return result;
                                };
                            }

                            /**
                             * Creates a function like `_.over`.
                             *
                             * @private
                             * @param {Function} arrayFunc The function to iterate over iteratees.
                             * @returns {Function} Returns the new over function.
                             */
                            function createOver(arrayFunc) {
                                return flatRest(function (iteratees) {
                                    iteratees = arrayMap(iteratees, baseUnary(getIteratee()));
                                    return baseRest(function (args) {
                                        var thisArg = this;
                                        return arrayFunc(iteratees, function (iteratee) {
                                            return apply(iteratee, thisArg, args);
                                        });
                                    });
                                });
                            }

                            /**
                             * Creates the padding for `string` based on `length`. The `chars` string
                             * is truncated if the number of characters exceeds `length`.
                             *
                             * @private
                             * @param {number} length The padding length.
                             * @param {string} [chars=' '] The string used as padding.
                             * @returns {string} Returns the padding for `string`.
                             */
                            function createPadding(length, chars) {
                                chars = chars === undefined ? ' ' : baseToString(chars);

                                var charsLength = chars.length;
                                if (charsLength < 2) {
                                    return charsLength ? baseRepeat(chars, length) : chars;
                                }
                                var result = baseRepeat(chars, nativeCeil(length / stringSize(chars)));
                                return hasUnicode(chars)
                                    ? castSlice(stringToArray(result), 0, length).join('')
                                    : result.slice(0, length);
                            }

                            /**
                             * Creates a function that wraps `func` to invoke it with the `this` binding
                             * of `thisArg` and `partials` prepended to the arguments it receives.
                             *
                             * @private
                             * @param {Function} func The function to wrap.
                             * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
                             * @param {*} thisArg The `this` binding of `func`.
                             * @param {Array} partials The arguments to prepend to those provided to
                             *  the new function.
                             * @returns {Function} Returns the new wrapped function.
                             */
                            function createPartial(func, bitmask, thisArg, partials) {
                                var isBind = bitmask & WRAP_BIND_FLAG,
                                    Ctor = createCtor(func);

                                function wrapper() {
                                    var argsIndex = -1,
                                        argsLength = arguments.length,
                                        leftIndex = -1,
                                        leftLength = partials.length,
                                        args = Array(leftLength + argsLength),
                                        fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;

                                    while (++leftIndex < leftLength) {
                                        args[leftIndex] = partials[leftIndex];
                                    }
                                    while (argsLength--) {
                                        args[leftIndex++] = arguments[++argsIndex];
                                    }
                                    return apply(fn, isBind ? thisArg : this, args);
                                }
                                return wrapper;
                            }

                            /**
                             * Creates a `_.range` or `_.rangeRight` function.
                             *
                             * @private
                             * @param {boolean} [fromRight] Specify iterating from right to left.
                             * @returns {Function} Returns the new range function.
                             */
                            function createRange(fromRight) {
                                return function (start, end, step) {
                                    if (step && typeof step != 'number' && isIterateeCall(start, end, step)) {
                                        end = step = undefined;
                                    }
                                    // Ensure the sign of `-0` is preserved.
                                    start = toFinite(start);
                                    if (end === undefined) {
                                        end = start;
                                        start = 0;
                                    } else {
                                        end = toFinite(end);
                                    }
                                    step = step === undefined ? (start < end ? 1 : -1) : toFinite(step);
                                    return baseRange(start, end, step, fromRight);
                                };
                            }

                            /**
                             * Creates a function that performs a relational operation on two values.
                             *
                             * @private
                             * @param {Function} operator The function to perform the operation.
                             * @returns {Function} Returns the new relational operation function.
                             */
                            function createRelationalOperation(operator) {
                                return function (value, other) {
                                    if (!(typeof value == 'string' && typeof other == 'string')) {
                                        value = toNumber(value);
                                        other = toNumber(other);
                                    }
                                    return operator(value, other);
                                };
                            }

                            /**
                             * Creates a function that wraps `func` to continue currying.
                             *
                             * @private
                             * @param {Function} func The function to wrap.
                             * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
                             * @param {Function} wrapFunc The function to create the `func` wrapper.
                             * @param {*} placeholder The placeholder value.
                             * @param {*} [thisArg] The `this` binding of `func`.
                             * @param {Array} [partials] The arguments to prepend to those provided to
                             *  the new function.
                             * @param {Array} [holders] The `partials` placeholder indexes.
                             * @param {Array} [argPos] The argument positions of the new function.
                             * @param {number} [ary] The arity cap of `func`.
                             * @param {number} [arity] The arity of `func`.
                             * @returns {Function} Returns the new wrapped function.
                             */
                            function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
                                var isCurry = bitmask & WRAP_CURRY_FLAG,
                                    newHolders = isCurry ? holders : undefined,
                                    newHoldersRight = isCurry ? undefined : holders,
                                    newPartials = isCurry ? partials : undefined,
                                    newPartialsRight = isCurry ? undefined : partials;

                                bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG);
                                bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG);

                                if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) {
                                    bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG);
                                }
                                var newData = [
                                    func, bitmask, thisArg, newPartials, newHolders, newPartialsRight,
                                    newHoldersRight, argPos, ary, arity
                                ];

                                var result = wrapFunc.apply(undefined, newData);
                                if (isLaziable(func)) {
                                    setData(result, newData);
                                }
                                result.placeholder = placeholder;
                                return setWrapToString(result, func, bitmask);
                            }

                            /**
                             * Creates a function like `_.round`.
                             *
                             * @private
                             * @param {string} methodName The name of the `Math` method to use when rounding.
                             * @returns {Function} Returns the new round function.
                             */
                            function createRound(methodName) {
                                var func = Math[methodName];
                                return function (number, precision) {
                                    number = toNumber(number);
                                    precision = precision == null ? 0 : nativeMin(toInteger(precision), 292);
                                    if (precision && nativeIsFinite(number)) {
                                        // Shift with exponential notation to avoid floating-point issues.
                                        // See [MDN](https://mdn.io/round#Examples) for more details.
                                        var pair = (toString(number) + 'e').split('e'),
                                            value = func(pair[0] + 'e' + (+pair[1] + precision));

                                        pair = (toString(value) + 'e').split('e');
                                        return +(pair[0] + 'e' + (+pair[1] - precision));
                                    }
                                    return func(number);
                                };
                            }

                            /**
                             * Creates a set object of `values`.
                             *
                             * @private
                             * @param {Array} values The values to add to the set.
                             * @returns {Object} Returns the new set.
                             */
                            var createSet = !(Set && (1 / setToArray(new Set([, -0]))[1]) == INFINITY) ? noop : function (values) {
                                return new Set(values);
                            };

                            /**
                             * Creates a `_.toPairs` or `_.toPairsIn` function.
                             *
                             * @private
                             * @param {Function} keysFunc The function to get the keys of a given object.
                             * @returns {Function} Returns the new pairs function.
                             */
                            function createToPairs(keysFunc) {
                                return function (object) {
                                    var tag = getTag(object);
                                    if (tag == mapTag) {
                                        return mapToArray(object);
                                    }
                                    if (tag == setTag) {
                                        return setToPairs(object);
                                    }
                                    return baseToPairs(object, keysFunc(object));
                                };
                            }

                            /**
                             * Creates a function that either curries or invokes `func` with optional
                             * `this` binding and partially applied arguments.
                             *
                             * @private
                             * @param {Function|string} func The function or method name to wrap.
                             * @param {number} bitmask The bitmask flags.
                             *    1 - `_.bind`
                             *    2 - `_.bindKey`
                             *    4 - `_.curry` or `_.curryRight` of a bound function
                             *    8 - `_.curry`
                             *   16 - `_.curryRight`
                             *   32 - `_.partial`
                             *   64 - `_.partialRight`
                             *  128 - `_.rearg`
                             *  256 - `_.ary`
                             *  512 - `_.flip`
                             * @param {*} [thisArg] The `this` binding of `func`.
                             * @param {Array} [partials] The arguments to be partially applied.
                             * @param {Array} [holders] The `partials` placeholder indexes.
                             * @param {Array} [argPos] The argument positions of the new function.
                             * @param {number} [ary] The arity cap of `func`.
                             * @param {number} [arity] The arity of `func`.
                             * @returns {Function} Returns the new wrapped function.
                             */
                            function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
                                var isBindKey = bitmask & WRAP_BIND_KEY_FLAG;
                                if (!isBindKey && typeof func != 'function') {
                                    throw new TypeError(FUNC_ERROR_TEXT);
                                }
                                var length = partials ? partials.length : 0;
                                if (!length) {
                                    bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG);
                                    partials = holders = undefined;
                                }
                                ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0);
                                arity = arity === undefined ? arity : toInteger(arity);
                                length -= holders ? holders.length : 0;

                                if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) {
                                    var partialsRight = partials,
                                        holdersRight = holders;

                                    partials = holders = undefined;
                                }
                                var data = isBindKey ? undefined : getData(func);

                                var newData = [
                                    func, bitmask, thisArg, partials, holders, partialsRight, holdersRight,
                                    argPos, ary, arity
                                ];

                                if (data) {
                                    mergeData(newData, data);
                                }
                                func = newData[0];
                                bitmask = newData[1];
                                thisArg = newData[2];
                                partials = newData[3];
                                holders = newData[4];
                                arity = newData[9] = newData[9] === undefined
                                    ? (isBindKey ? 0 : func.length)
                                    : nativeMax(newData[9] - length, 0);

                                if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) {
                                    bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG);
                                }
                                if (!bitmask || bitmask == WRAP_BIND_FLAG) {
                                    var result = createBind(func, bitmask, thisArg);
                                } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) {
                                    result = createCurry(func, bitmask, arity);
                                } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) {
                                    result = createPartial(func, bitmask, thisArg, partials);
                                } else {
                                    result = createHybrid.apply(undefined, newData);
                                }
                                var setter = data ? baseSetData : setData;
                                return setWrapToString(setter(result, newData), func, bitmask);
                            }

                            /**
                             * Used by `_.defaults` to customize its `_.assignIn` use to assign properties
                             * of source objects to the destination object for all destination properties
                             * that resolve to `undefined`.
                             *
                             * @private
                             * @param {*} objValue The destination value.
                             * @param {*} srcValue The source value.
                             * @param {string} key The key of the property to assign.
                             * @param {Object} object The parent object of `objValue`.
                             * @returns {*} Returns the value to assign.
                             */
                            function customDefaultsAssignIn(objValue, srcValue, key, object) {
                                if (objValue === undefined ||
                                    (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) {
                                    return srcValue;
                                }
                                return objValue;
                            }

                            /**
                             * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source
                             * objects into destination objects that are passed thru.
                             *
                             * @private
                             * @param {*} objValue The destination value.
                             * @param {*} srcValue The source value.
                             * @param {string} key The key of the property to merge.
                             * @param {Object} object The parent object of `objValue`.
                             * @param {Object} source The parent object of `srcValue`.
                             * @param {Object} [stack] Tracks traversed source values and their merged
                             *  counterparts.
                             * @returns {*} Returns the value to assign.
                             */
                            function customDefaultsMerge(objValue, srcValue, key, object, source, stack) {
                                if (isObject(objValue) && isObject(srcValue)) {
                                    // Recursively merge objects and arrays (susceptible to call stack limits).
                                    stack.set(srcValue, objValue);
                                    baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack);
                                    stack['delete'](srcValue);
                                }
                                return objValue;
                            }

                            /**
                             * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain
                             * objects.
                             *
                             * @private
                             * @param {*} value The value to inspect.
                             * @param {string} key The key of the property to inspect.
                             * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`.
                             */
                            function customOmitClone(value) {
                                return isPlainObject(value) ? undefined : value;
                            }

                            /**
                             * A specialized version of `baseIsEqualDeep` for arrays with support for
                             * partial deep comparisons.
                             *
                             * @private
                             * @param {Array} array The array to compare.
                             * @param {Array} other The other array to compare.
                             * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
                             * @param {Function} customizer The function to customize comparisons.
                             * @param {Function} equalFunc The function to determine equivalents of values.
                             * @param {Object} stack Tracks traversed `array` and `other` objects.
                             * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
                             */
                            function equalArrays(array, other, bitmask, customizer, equalFunc, stack) {
                                var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
                                    arrLength = array.length,
                                    othLength = other.length;

                                if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
                                    return false;
                                }
                                // Check that cyclic values are equal.
                                var arrStacked = stack.get(array);
                                var othStacked = stack.get(other);
                                if (arrStacked && othStacked) {
                                    return arrStacked == other && othStacked == array;
                                }
                                var index = -1,
                                    result = true,
                                    seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;

                                stack.set(array, other);
                                stack.set(other, array);

                                // Ignore non-index properties.
                                while (++index < arrLength) {
                                    var arrValue = array[index],
                                        othValue = other[index];

                                    if (customizer) {
                                        var compared = isPartial
                                            ? customizer(othValue, arrValue, index, other, array, stack)
                                            : customizer(arrValue, othValue, index, array, other, stack);
                                    }
                                    if (compared !== undefined) {
                                        if (compared) {
                                            continue;
                                        }
                                        result = false;
                                        break;
                                    }
                                    // Recursively compare arrays (susceptible to call stack limits).
                                    if (seen) {
                                        if (!arraySome(other, function (othValue, othIndex) {
                                            if (!cacheHas(seen, othIndex) &&
                                                (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {
                                                return seen.push(othIndex);
                                            }
                                        })) {
                                            result = false;
                                            break;
                                        }
                                    } else if (!(
                                        arrValue === othValue ||
                                        equalFunc(arrValue, othValue, bitmask, customizer, stack)
                                    )) {
                                        result = false;
                                        break;
                                    }
                                }
                                stack['delete'](array);
                                stack['delete'](other);
                                return result;
                            }

                            /**
                             * A specialized version of `baseIsEqualDeep` for comparing objects of
                             * the same `toStringTag`.
                             *
                             * **Note:** This function only supports comparing values with tags of
                             * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
                             *
                             * @private
                             * @param {Object} object The object to compare.
                             * @param {Object} other The other object to compare.
                             * @param {string} tag The `toStringTag` of the objects to compare.
                             * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
                             * @param {Function} customizer The function to customize comparisons.
                             * @param {Function} equalFunc The function to determine equivalents of values.
                             * @param {Object} stack Tracks traversed `object` and `other` objects.
                             * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
                             */
                            function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {
                                switch (tag) {
                                    case dataViewTag:
                                        if ((object.byteLength != other.byteLength) ||
                                            (object.byteOffset != other.byteOffset)) {
                                            return false;
                                        }
                                        object = object.buffer;
                                        other = other.buffer;

                                    case arrayBufferTag:
                                        if ((object.byteLength != other.byteLength) ||
                                            !equalFunc(new Uint8Array(object), new Uint8Array(other))) {
                                            return false;
                                        }
                                        return true;

                                    case boolTag:
                                    case dateTag:
                                    case numberTag:
                                        // Coerce booleans to `1` or `0` and dates to milliseconds.
                                        // Invalid dates are coerced to `NaN`.
                                        return eq(+object, +other);

                                    case errorTag:
                                        return object.name == other.name && object.message == other.message;

                                    case regexpTag:
                                    case stringTag:
                                        // Coerce regexes to strings and treat strings, primitives and objects,
                                        // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring
                                        // for more details.
                                        return object == (other + '');

                                    case mapTag:
                                        var convert = mapToArray;

                                    case setTag:
                                        var isPartial = bitmask & COMPARE_PARTIAL_FLAG;
                                        convert || (convert = setToArray);

                                        if (object.size != other.size && !isPartial) {
                                            return false;
                                        }
                                        // Assume cyclic values are equal.
                                        var stacked = stack.get(object);
                                        if (stacked) {
                                            return stacked == other;
                                        }
                                        bitmask |= COMPARE_UNORDERED_FLAG;

                                        // Recursively compare objects (susceptible to call stack limits).
                                        stack.set(object, other);
                                        var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);
                                        stack['delete'](object);
                                        return result;

                                    case symbolTag:
                                        if (symbolValueOf) {
                                            return symbolValueOf.call(object) == symbolValueOf.call(other);
                                        }
                                }
                                return false;
                            }

                            /**
                             * A specialized version of `baseIsEqualDeep` for objects with support for
                             * partial deep comparisons.
                             *
                             * @private
                             * @param {Object} object The object to compare.
                             * @param {Object} other The other object to compare.
                             * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
                             * @param {Function} customizer The function to customize comparisons.
                             * @param {Function} equalFunc The function to determine equivalents of values.
                             * @param {Object} stack Tracks traversed `object` and `other` objects.
                             * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
                             */
                            function equalObjects(object, other, bitmask, customizer, equalFunc, stack) {
                                var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
                                    objProps = getAllKeys(object),
                                    objLength = objProps.length,
                                    othProps = getAllKeys(other),
                                    othLength = othProps.length;

                                if (objLength != othLength && !isPartial) {
                                    return false;
                                }
                                var index = objLength;
                                while (index--) {
                                    var key = objProps[index];
                                    if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {
                                        return false;
                                    }
                                }
                                // Check that cyclic values are equal.
                                var objStacked = stack.get(object);
                                var othStacked = stack.get(other);
                                if (objStacked && othStacked) {
                                    return objStacked == other && othStacked == object;
                                }
                                var result = true;
                                stack.set(object, other);
                                stack.set(other, object);

                                var skipCtor = isPartial;
                                while (++index < objLength) {
                                    key = objProps[index];
                                    var objValue = object[key],
                                        othValue = other[key];

                                    if (customizer) {
                                        var compared = isPartial
                                            ? customizer(othValue, objValue, key, other, object, stack)
                                            : customizer(objValue, othValue, key, object, other, stack);
                                    }
                                    // Recursively compare objects (susceptible to call stack limits).
                                    if (!(compared === undefined
                                        ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))
                                        : compared
                                    )) {
                                        result = false;
                                        break;
                                    }
                                    skipCtor || (skipCtor = key == 'constructor');
                                }
                                if (result && !skipCtor) {
                                    var objCtor = object.constructor,
                                        othCtor = other.constructor;

                                    // Non `Object` object instances with different constructors are not equal.
                                    if (objCtor != othCtor &&
                                        ('constructor' in object && 'constructor' in other) &&
                                        !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
                                            typeof othCtor == 'function' && othCtor instanceof othCtor)) {
                                        result = false;
                                    }
                                }
                                stack['delete'](object);
                                stack['delete'](other);
                                return result;
                            }

                            /**
                             * A specialized version of `baseRest` which flattens the rest array.
                             *
                             * @private
                             * @param {Function} func The function to apply a rest parameter to.
                             * @returns {Function} Returns the new function.
                             */
                            function flatRest(func) {
                                return setToString(overRest(func, undefined, flatten), func + '');
                            }

                            /**
                             * Creates an array of own enumerable property names and symbols of `object`.
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @returns {Array} Returns the array of property names and symbols.
                             */
                            function getAllKeys(object) {
                                return baseGetAllKeys(object, keys, getSymbols);
                            }

                            /**
                             * Creates an array of own and inherited enumerable property names and
                             * symbols of `object`.
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @returns {Array} Returns the array of property names and symbols.
                             */
                            function getAllKeysIn(object) {
                                return baseGetAllKeys(object, keysIn, getSymbolsIn);
                            }

                            /**
                             * Gets metadata for `func`.
                             *
                             * @private
                             * @param {Function} func The function to query.
                             * @returns {*} Returns the metadata for `func`.
                             */
                            var getData = !metaMap ? noop : function (func) {
                                return metaMap.get(func);
                            };

                            /**
                             * Gets the name of `func`.
                             *
                             * @private
                             * @param {Function} func The function to query.
                             * @returns {string} Returns the function name.
                             */
                            function getFuncName(func) {
                                var result = (func.name + ''),
                                    array = realNames[result],
                                    length = hasOwnProperty.call(realNames, result) ? array.length : 0;

                                while (length--) {
                                    var data = array[length],
                                        otherFunc = data.func;
                                    if (otherFunc == null || otherFunc == func) {
                                        return data.name;
                                    }
                                }
                                return result;
                            }

                            /**
                             * Gets the argument placeholder value for `func`.
                             *
                             * @private
                             * @param {Function} func The function to inspect.
                             * @returns {*} Returns the placeholder value.
                             */
                            function getHolder(func) {
                                var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
                                return object.placeholder;
                            }

                            /**
                             * Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
                             * this function returns the custom method, otherwise it returns `baseIteratee`.
                             * If arguments are provided, the chosen function is invoked with them and
                             * its result is returned.
                             *
                             * @private
                             * @param {*} [value] The value to convert to an iteratee.
                             * @param {number} [arity] The arity of the created iteratee.
                             * @returns {Function} Returns the chosen function or its result.
                             */
                            function getIteratee() {
                                var result = lodash.iteratee || iteratee;
                                result = result === iteratee ? baseIteratee : result;
                                return arguments.length ? result(arguments[0], arguments[1]) : result;
                            }

                            /**
                             * Gets the data for `map`.
                             *
                             * @private
                             * @param {Object} map The map to query.
                             * @param {string} key The reference key.
                             * @returns {*} Returns the map data.
                             */
                            function getMapData(map, key) {
                                var data = map.__data__;
                                return isKeyable(key)
                                    ? data[typeof key == 'string' ? 'string' : 'hash']
                                    : data.map;
                            }

                            /**
                             * Gets the property names, values, and compare flags of `object`.
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @returns {Array} Returns the match data of `object`.
                             */
                            function getMatchData(object) {
                                var result = keys(object),
                                    length = result.length;

                                while (length--) {
                                    var key = result[length],
                                        value = object[key];

                                    result[length] = [key, value, isStrictComparable(value)];
                                }
                                return result;
                            }

                            /**
                             * Gets the native function at `key` of `object`.
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @param {string} key The key of the method to get.
                             * @returns {*} Returns the function if it's native, else `undefined`.
                             */
                            function getNative(object, key) {
                                var value = getValue(object, key);
                                return baseIsNative(value) ? value : undefined;
                            }

                            /**
                             * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
                             *
                             * @private
                             * @param {*} value The value to query.
                             * @returns {string} Returns the raw `toStringTag`.
                             */
                            function getRawTag(value) {
                                var isOwn = hasOwnProperty.call(value, symToStringTag),
                                    tag = value[symToStringTag];

                                try {
                                    value[symToStringTag] = undefined;
                                    var unmasked = true;
                                } catch (e) { }

                                var result = nativeObjectToString.call(value);
                                if (unmasked) {
                                    if (isOwn) {
                                        value[symToStringTag] = tag;
                                    } else {
                                        delete value[symToStringTag];
                                    }
                                }
                                return result;
                            }

                            /**
                             * Creates an array of the own enumerable symbols of `object`.
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @returns {Array} Returns the array of symbols.
                             */
                            var getSymbols = !nativeGetSymbols ? stubArray : function (object) {
                                if (object == null) {
                                    return [];
                                }
                                object = Object(object);
                                return arrayFilter(nativeGetSymbols(object), function (symbol) {
                                    return propertyIsEnumerable.call(object, symbol);
                                });
                            };

                            /**
                             * Creates an array of the own and inherited enumerable symbols of `object`.
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @returns {Array} Returns the array of symbols.
                             */
                            var getSymbolsIn = !nativeGetSymbols ? stubArray : function (object) {
                                var result = [];
                                while (object) {
                                    arrayPush(result, getSymbols(object));
                                    object = getPrototype(object);
                                }
                                return result;
                            };

                            /**
                             * Gets the `toStringTag` of `value`.
                             *
                             * @private
                             * @param {*} value The value to query.
                             * @returns {string} Returns the `toStringTag`.
                             */
                            var getTag = baseGetTag;

                            // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.
                            if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
                                (Map && getTag(new Map) != mapTag) ||
                                (Promise && getTag(Promise.resolve()) != promiseTag) ||
                                (Set && getTag(new Set) != setTag) ||
                                (WeakMap && getTag(new WeakMap) != weakMapTag)) {
                                getTag = function (value) {
                                    var result = baseGetTag(value),
                                        Ctor = result == objectTag ? value.constructor : undefined,
                                        ctorString = Ctor ? toSource(Ctor) : '';

                                    if (ctorString) {
                                        switch (ctorString) {
                                            case dataViewCtorString: return dataViewTag;
                                            case mapCtorString: return mapTag;
                                            case promiseCtorString: return promiseTag;
                                            case setCtorString: return setTag;
                                            case weakMapCtorString: return weakMapTag;
                                        }
                                    }
                                    return result;
                                };
                            }

                            /**
                             * Gets the view, applying any `transforms` to the `start` and `end` positions.
                             *
                             * @private
                             * @param {number} start The start of the view.
                             * @param {number} end The end of the view.
                             * @param {Array} transforms The transformations to apply to the view.
                             * @returns {Object} Returns an object containing the `start` and `end`
                             *  positions of the view.
                             */
                            function getView(start, end, transforms) {
                                var index = -1,
                                    length = transforms.length;

                                while (++index < length) {
                                    var data = transforms[index],
                                        size = data.size;

                                    switch (data.type) {
                                        case 'drop': start += size; break;
                                        case 'dropRight': end -= size; break;
                                        case 'take': end = nativeMin(end, start + size); break;
                                        case 'takeRight': start = nativeMax(start, end - size); break;
                                    }
                                }
                                return { 'start': start, 'end': end };
                            }

                            /**
                             * Extracts wrapper details from the `source` body comment.
                             *
                             * @private
                             * @param {string} source The source to inspect.
                             * @returns {Array} Returns the wrapper details.
                             */
                            function getWrapDetails(source) {
                                var match = source.match(reWrapDetails);
                                return match ? match[1].split(reSplitDetails) : [];
                            }

                            /**
                             * Checks if `path` exists on `object`.
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @param {Array|string} path The path to check.
                             * @param {Function} hasFunc The function to check properties.
                             * @returns {boolean} Returns `true` if `path` exists, else `false`.
                             */
                            function hasPath(object, path, hasFunc) {
                                path = castPath(path, object);

                                var index = -1,
                                    length = path.length,
                                    result = false;

                                while (++index < length) {
                                    var key = toKey(path[index]);
                                    if (!(result = object != null && hasFunc(object, key))) {
                                        break;
                                    }
                                    object = object[key];
                                }
                                if (result || ++index != length) {
                                    return result;
                                }
                                length = object == null ? 0 : object.length;
                                return !!length && isLength(length) && isIndex(key, length) &&
                                    (isArray(object) || isArguments(object));
                            }

                            /**
                             * Initializes an array clone.
                             *
                             * @private
                             * @param {Array} array The array to clone.
                             * @returns {Array} Returns the initialized clone.
                             */
                            function initCloneArray(array) {
                                var length = array.length,
                                    result = new array.constructor(length);

                                // Add properties assigned by `RegExp#exec`.
                                if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
                                    result.index = array.index;
                                    result.input = array.input;
                                }
                                return result;
                            }

                            /**
                             * Initializes an object clone.
                             *
                             * @private
                             * @param {Object} object The object to clone.
                             * @returns {Object} Returns the initialized clone.
                             */
                            function initCloneObject(object) {
                                return (typeof object.constructor == 'function' && !isPrototype(object))
                                    ? baseCreate(getPrototype(object))
                                    : {};
                            }

                            /**
                             * Initializes an object clone based on its `toStringTag`.
                             *
                             * **Note:** This function only supports cloning values with tags of
                             * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.
                             *
                             * @private
                             * @param {Object} object The object to clone.
                             * @param {string} tag The `toStringTag` of the object to clone.
                             * @param {boolean} [isDeep] Specify a deep clone.
                             * @returns {Object} Returns the initialized clone.
                             */
                            function initCloneByTag(object, tag, isDeep) {
                                var Ctor = object.constructor;
                                switch (tag) {
                                    case arrayBufferTag:
                                        return cloneArrayBuffer(object);

                                    case boolTag:
                                    case dateTag:
                                        return new Ctor(+object);

                                    case dataViewTag:
                                        return cloneDataView(object, isDeep);

                                    case float32Tag: case float64Tag:
                                    case int8Tag: case int16Tag: case int32Tag:
                                    case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
                                        return cloneTypedArray(object, isDeep);

                                    case mapTag:
                                        return new Ctor;

                                    case numberTag:
                                    case stringTag:
                                        return new Ctor(object);

                                    case regexpTag:
                                        return cloneRegExp(object);

                                    case setTag:
                                        return new Ctor;

                                    case symbolTag:
                                        return cloneSymbol(object);
                                }
                            }

                            /**
                             * Inserts wrapper `details` in a comment at the top of the `source` body.
                             *
                             * @private
                             * @param {string} source The source to modify.
                             * @returns {Array} details The details to insert.
                             * @returns {string} Returns the modified source.
                             */
                            function insertWrapDetails(source, details) {
                                var length = details.length;
                                if (!length) {
                                    return source;
                                }
                                var lastIndex = length - 1;
                                details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex];
                                details = details.join(length > 2 ? ', ' : ' ');
                                return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n');
                            }

                            /**
                             * Checks if `value` is a flattenable `arguments` object or array.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
                             */
                            function isFlattenable(value) {
                                return isArray(value) || isArguments(value) ||
                                    !!(spreadableSymbol && value && value[spreadableSymbol]);
                            }

                            /**
                             * Checks if `value` is a valid array-like index.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
                             * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
                             */
                            function isIndex(value, length) {
                                var type = typeof value;
                                length = length == null ? MAX_SAFE_INTEGER : length;

                                return !!length &&
                                    (type == 'number' ||
                                        (type != 'symbol' && reIsUint.test(value))) &&
                                    (value > -1 && value % 1 == 0 && value < length);
                            }

                            /**
                             * Checks if the given arguments are from an iteratee call.
                             *
                             * @private
                             * @param {*} value The potential iteratee value argument.
                             * @param {*} index The potential iteratee index or key argument.
                             * @param {*} object The potential iteratee object argument.
                             * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
                             *  else `false`.
                             */
                            function isIterateeCall(value, index, object) {
                                if (!isObject(object)) {
                                    return false;
                                }
                                var type = typeof index;
                                if (type == 'number'
                                    ? (isArrayLike(object) && isIndex(index, object.length))
                                    : (type == 'string' && index in object)
                                ) {
                                    return eq(object[index], value);
                                }
                                return false;
                            }

                            /**
                             * Checks if `value` is a property name and not a property path.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @param {Object} [object] The object to query keys on.
                             * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
                             */
                            function isKey(value, object) {
                                if (isArray(value)) {
                                    return false;
                                }
                                var type = typeof value;
                                if (type == 'number' || type == 'symbol' || type == 'boolean' ||
                                    value == null || isSymbol(value)) {
                                    return true;
                                }
                                return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
                                    (object != null && value in Object(object));
                            }

                            /**
                             * Checks if `value` is suitable for use as unique object key.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
                             */
                            function isKeyable(value) {
                                var type = typeof value;
                                return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
                                    ? (value !== '__proto__')
                                    : (value === null);
                            }

                            /**
                             * Checks if `func` has a lazy counterpart.
                             *
                             * @private
                             * @param {Function} func The function to check.
                             * @returns {boolean} Returns `true` if `func` has a lazy counterpart,
                             *  else `false`.
                             */
                            function isLaziable(func) {
                                var funcName = getFuncName(func),
                                    other = lodash[funcName];

                                if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
                                    return false;
                                }
                                if (func === other) {
                                    return true;
                                }
                                var data = getData(other);
                                return !!data && func === data[0];
                            }

                            /**
                             * Checks if `func` has its source masked.
                             *
                             * @private
                             * @param {Function} func The function to check.
                             * @returns {boolean} Returns `true` if `func` is masked, else `false`.
                             */
                            function isMasked(func) {
                                return !!maskSrcKey && (maskSrcKey in func);
                            }

                            /**
                             * Checks if `func` is capable of being masked.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `func` is maskable, else `false`.
                             */
                            var isMaskable = coreJsData ? isFunction : stubFalse;

                            /**
                             * Checks if `value` is likely a prototype object.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
                             */
                            function isPrototype(value) {
                                var Ctor = value && value.constructor,
                                    proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;

                                return value === proto;
                            }

                            /**
                             * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
                             *
                             * @private
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` if suitable for strict
                             *  equality comparisons, else `false`.
                             */
                            function isStrictComparable(value) {
                                return value === value && !isObject(value);
                            }

                            /**
                             * A specialized version of `matchesProperty` for source values suitable
                             * for strict equality comparisons, i.e. `===`.
                             *
                             * @private
                             * @param {string} key The key of the property to get.
                             * @param {*} srcValue The value to match.
                             * @returns {Function} Returns the new spec function.
                             */
                            function matchesStrictComparable(key, srcValue) {
                                return function (object) {
                                    if (object == null) {
                                        return false;
                                    }
                                    return object[key] === srcValue &&
                                        (srcValue !== undefined || (key in Object(object)));
                                };
                            }

                            /**
                             * A specialized version of `_.memoize` which clears the memoized function's
                             * cache when it exceeds `MAX_MEMOIZE_SIZE`.
                             *
                             * @private
                             * @param {Function} func The function to have its output memoized.
                             * @returns {Function} Returns the new memoized function.
                             */
                            function memoizeCapped(func) {
                                var result = memoize(func, function (key) {
                                    if (cache.size === MAX_MEMOIZE_SIZE) {
                                        cache.clear();
                                    }
                                    return key;
                                });

                                var cache = result.cache;
                                return result;
                            }

                            /**
                             * Merges the function metadata of `source` into `data`.
                             *
                             * Merging metadata reduces the number of wrappers used to invoke a function.
                             * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
                             * may be applied regardless of execution order. Methods like `_.ary` and
                             * `_.rearg` modify function arguments, making the order in which they are
                             * executed important, preventing the merging of metadata. However, we make
                             * an exception for a safe combined case where curried functions have `_.ary`
                             * and or `_.rearg` applied.
                             *
                             * @private
                             * @param {Array} data The destination metadata.
                             * @param {Array} source The source metadata.
                             * @returns {Array} Returns `data`.
                             */
                            function mergeData(data, source) {
                                var bitmask = data[1],
                                    srcBitmask = source[1],
                                    newBitmask = bitmask | srcBitmask,
                                    isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG);

                                var isCombo =
                                    ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) ||
                                    ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) ||
                                    ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG));

                                // Exit early if metadata can't be merged.
                                if (!(isCommon || isCombo)) {
                                    return data;
                                }
                                // Use source `thisArg` if available.
                                if (srcBitmask & WRAP_BIND_FLAG) {
                                    data[2] = source[2];
                                    // Set when currying a bound function.
                                    newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG;
                                }
                                // Compose partial arguments.
                                var value = source[3];
                                if (value) {
                                    var partials = data[3];
                                    data[3] = partials ? composeArgs(partials, value, source[4]) : value;
                                    data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4];
                                }
                                // Compose partial right arguments.
                                value = source[5];
                                if (value) {
                                    partials = data[5];
                                    data[5] = partials ? composeArgsRight(partials, value, source[6]) : value;
                                    data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6];
                                }
                                // Use source `argPos` if available.
                                value = source[7];
                                if (value) {
                                    data[7] = value;
                                }
                                // Use source `ary` if it's smaller.
                                if (srcBitmask & WRAP_ARY_FLAG) {
                                    data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
                                }
                                // Use source `arity` if one is not provided.
                                if (data[9] == null) {
                                    data[9] = source[9];
                                }
                                // Use source `func` and merge bitmasks.
                                data[0] = source[0];
                                data[1] = newBitmask;

                                return data;
                            }

                            /**
                             * This function is like
                             * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
                             * except that it includes inherited enumerable properties.
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @returns {Array} Returns the array of property names.
                             */
                            function nativeKeysIn(object) {
                                var result = [];
                                if (object != null) {
                                    for (var key in Object(object)) {
                                        result.push(key);
                                    }
                                }
                                return result;
                            }

                            /**
                             * Converts `value` to a string using `Object.prototype.toString`.
                             *
                             * @private
                             * @param {*} value The value to convert.
                             * @returns {string} Returns the converted string.
                             */
                            function objectToString(value) {
                                return nativeObjectToString.call(value);
                            }

                            /**
                             * A specialized version of `baseRest` which transforms the rest array.
                             *
                             * @private
                             * @param {Function} func The function to apply a rest parameter to.
                             * @param {number} [start=func.length-1] The start position of the rest parameter.
                             * @param {Function} transform The rest array transform.
                             * @returns {Function} Returns the new function.
                             */
                            function overRest(func, start, transform) {
                                start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
                                return function () {
                                    var args = arguments,
                                        index = -1,
                                        length = nativeMax(args.length - start, 0),
                                        array = Array(length);

                                    while (++index < length) {
                                        array[index] = args[start + index];
                                    }
                                    index = -1;
                                    var otherArgs = Array(start + 1);
                                    while (++index < start) {
                                        otherArgs[index] = args[index];
                                    }
                                    otherArgs[start] = transform(array);
                                    return apply(func, this, otherArgs);
                                };
                            }

                            /**
                             * Gets the parent value at `path` of `object`.
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @param {Array} path The path to get the parent value of.
                             * @returns {*} Returns the parent value.
                             */
                            function parent(object, path) {
                                return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));
                            }

                            /**
                             * Reorder `array` according to the specified indexes where the element at
                             * the first index is assigned as the first element, the element at
                             * the second index is assigned as the second element, and so on.
                             *
                             * @private
                             * @param {Array} array The array to reorder.
                             * @param {Array} indexes The arranged array indexes.
                             * @returns {Array} Returns `array`.
                             */
                            function reorder(array, indexes) {
                                var arrLength = array.length,
                                    length = nativeMin(indexes.length, arrLength),
                                    oldArray = copyArray(array);

                                while (length--) {
                                    var index = indexes[length];
                                    array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
                                }
                                return array;
                            }

                            /**
                             * Gets the value at `key`, unless `key` is "__proto__" or "constructor".
                             *
                             * @private
                             * @param {Object} object The object to query.
                             * @param {string} key The key of the property to get.
                             * @returns {*} Returns the property value.
                             */
                            function safeGet(object, key) {
                                if (key === 'constructor' && typeof object[key] === 'function') {
                                    return;
                                }

                                if (key == '__proto__') {
                                    return;
                                }

                                return object[key];
                            }

                            /**
                             * Sets metadata for `func`.
                             *
                             * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
                             * period of time, it will trip its breaker and transition to an identity
                             * function to avoid garbage collection pauses in V8. See
                             * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070)
                             * for more details.
                             *
                             * @private
                             * @param {Function} func The function to associate metadata with.
                             * @param {*} data The metadata.
                             * @returns {Function} Returns `func`.
                             */
                            var setData = shortOut(baseSetData);

                            /**
                             * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout).
                             *
                             * @private
                             * @param {Function} func The function to delay.
                             * @param {number} wait The number of milliseconds to delay invocation.
                             * @returns {number|Object} Returns the timer id or timeout object.
                             */
                            var setTimeout = ctxSetTimeout || function (func, wait) {
                                return root.setTimeout(func, wait);
                            };

                            /**
                             * Sets the `toString` method of `func` to return `string`.
                             *
                             * @private
                             * @param {Function} func The function to modify.
                             * @param {Function} string The `toString` result.
                             * @returns {Function} Returns `func`.
                             */
                            var setToString = shortOut(baseSetToString);

                            /**
                             * Sets the `toString` method of `wrapper` to mimic the source of `reference`
                             * with wrapper details in a comment at the top of the source body.
                             *
                             * @private
                             * @param {Function} wrapper The function to modify.
                             * @param {Function} reference The reference function.
                             * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
                             * @returns {Function} Returns `wrapper`.
                             */
                            function setWrapToString(wrapper, reference, bitmask) {
                                var source = (reference + '');
                                return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask)));
                            }

                            /**
                             * Creates a function that'll short out and invoke `identity` instead
                             * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`
                             * milliseconds.
                             *
                             * @private
                             * @param {Function} func The function to restrict.
                             * @returns {Function} Returns the new shortable function.
                             */
                            function shortOut(func) {
                                var count = 0,
                                    lastCalled = 0;

                                return function () {
                                    var stamp = nativeNow(),
                                        remaining = HOT_SPAN - (stamp - lastCalled);

                                    lastCalled = stamp;
                                    if (remaining > 0) {
                                        if (++count >= HOT_COUNT) {
                                            return arguments[0];
                                        }
                                    } else {
                                        count = 0;
                                    }
                                    return func.apply(undefined, arguments);
                                };
                            }

                            /**
                             * A specialized version of `_.shuffle` which mutates and sets the size of `array`.
                             *
                             * @private
                             * @param {Array} array The array to shuffle.
                             * @param {number} [size=array.length] The size of `array`.
                             * @returns {Array} Returns `array`.
                             */
                            function shuffleSelf(array, size) {
                                var index = -1,
                                    length = array.length,
                                    lastIndex = length - 1;

                                size = size === undefined ? length : size;
                                while (++index < size) {
                                    var rand = baseRandom(index, lastIndex),
                                        value = array[rand];

                                    array[rand] = array[index];
                                    array[index] = value;
                                }
                                array.length = size;
                                return array;
                            }

                            /**
                             * Converts `string` to a property path array.
                             *
                             * @private
                             * @param {string} string The string to convert.
                             * @returns {Array} Returns the property path array.
                             */
                            var stringToPath = memoizeCapped(function (string) {
                                var result = [];
                                if (string.charCodeAt(0) === 46 /* . */) {
                                    result.push('');
                                }
                                string.replace(rePropName, function (match, number, quote, subString) {
                                    result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match));
                                });
                                return result;
                            });

                            /**
                             * Converts `value` to a string key if it's not a string or symbol.
                             *
                             * @private
                             * @param {*} value The value to inspect.
                             * @returns {string|symbol} Returns the key.
                             */
                            function toKey(value) {
                                if (typeof value == 'string' || isSymbol(value)) {
                                    return value;
                                }
                                var result = (value + '');
                                return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
                            }

                            /**
                             * Converts `func` to its source code.
                             *
                             * @private
                             * @param {Function} func The function to convert.
                             * @returns {string} Returns the source code.
                             */
                            function toSource(func) {
                                if (func != null) {
                                    try {
                                        return funcToString.call(func);
                                    } catch (e) { }
                                    try {
                                        return (func + '');
                                    } catch (e) { }
                                }
                                return '';
                            }

                            /**
                             * Updates wrapper `details` based on `bitmask` flags.
                             *
                             * @private
                             * @returns {Array} details The details to modify.
                             * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
                             * @returns {Array} Returns `details`.
                             */
                            function updateWrapDetails(details, bitmask) {
                                arrayEach(wrapFlags, function (pair) {
                                    var value = '_.' + pair[0];
                                    if ((bitmask & pair[1]) && !arrayIncludes(details, value)) {
                                        details.push(value);
                                    }
                                });
                                return details.sort();
                            }

                            /**
                             * Creates a clone of `wrapper`.
                             *
                             * @private
                             * @param {Object} wrapper The wrapper to clone.
                             * @returns {Object} Returns the cloned wrapper.
                             */
                            function wrapperClone(wrapper) {
                                if (wrapper instanceof LazyWrapper) {
                                    return wrapper.clone();
                                }
                                var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__);
                                result.__actions__ = copyArray(wrapper.__actions__);
                                result.__index__ = wrapper.__index__;
                                result.__values__ = wrapper.__values__;
                                return result;
                            }

                            /*------------------------------------------------------------------------*/

                            /**
                             * Creates an array of elements split into groups the length of `size`.
                             * If `array` can't be split evenly, the final chunk will be the remaining
                             * elements.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Array
                             * @param {Array} array The array to process.
                             * @param {number} [size=1] The length of each chunk
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {Array} Returns the new array of chunks.
                             * @example
                             *
                             * _.chunk(['a', 'b', 'c', 'd'], 2);
                             * // => [['a', 'b'], ['c', 'd']]
                             *
                             * _.chunk(['a', 'b', 'c', 'd'], 3);
                             * // => [['a', 'b', 'c'], ['d']]
                             */
                            function chunk(array, size, guard) {
                                if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
                                    size = 1;
                                } else {
                                    size = nativeMax(toInteger(size), 0);
                                }
                                var length = array == null ? 0 : array.length;
                                if (!length || size < 1) {
                                    return [];
                                }
                                var index = 0,
                                    resIndex = 0,
                                    result = Array(nativeCeil(length / size));

                                while (index < length) {
                                    result[resIndex++] = baseSlice(array, index, (index += size));
                                }
                                return result;
                            }

                            /**
                             * Creates an array with all falsey values removed. The values `false`, `null`,
                             * `0`, `""`, `undefined`, and `NaN` are falsey.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Array
                             * @param {Array} array The array to compact.
                             * @returns {Array} Returns the new array of filtered values.
                             * @example
                             *
                             * _.compact([0, 1, false, 2, '', 3]);
                             * // => [1, 2, 3]
                             */
                            function compact(array) {
                                var index = -1,
                                    length = array == null ? 0 : array.length,
                                    resIndex = 0,
                                    result = [];

                                while (++index < length) {
                                    var value = array[index];
                                    if (value) {
                                        result[resIndex++] = value;
                                    }
                                }
                                return result;
                            }

                            /**
                             * Creates a new array concatenating `array` with any additional arrays
                             * and/or values.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The array to concatenate.
                             * @param {...*} [values] The values to concatenate.
                             * @returns {Array} Returns the new concatenated array.
                             * @example
                             *
                             * var array = [1];
                             * var other = _.concat(array, 2, [3], [[4]]);
                             *
                             * console.log(other);
                             * // => [1, 2, 3, [4]]
                             *
                             * console.log(array);
                             * // => [1]
                             */
                            function concat() {
                                var length = arguments.length;
                                if (!length) {
                                    return [];
                                }
                                var args = Array(length - 1),
                                    array = arguments[0],
                                    index = length;

                                while (index--) {
                                    args[index - 1] = arguments[index];
                                }
                                return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));
                            }

                            /**
                             * Creates an array of `array` values not included in the other given arrays
                             * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
                             * for equality comparisons. The order and references of result values are
                             * determined by the first array.
                             *
                             * **Note:** Unlike `_.pullAll`, this method returns a new array.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @param {...Array} [values] The values to exclude.
                             * @returns {Array} Returns the new array of filtered values.
                             * @see _.without, _.xor
                             * @example
                             *
                             * _.difference([2, 1], [2, 3]);
                             * // => [1]
                             */
                            var difference = baseRest(function (array, values) {
                                return isArrayLikeObject(array)
                                    ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
                                    : [];
                            });

                            /**
                             * This method is like `_.difference` except that it accepts `iteratee` which
                             * is invoked for each element of `array` and `values` to generate the criterion
                             * by which they're compared. The order and references of result values are
                             * determined by the first array. The iteratee is invoked with one argument:
                             * (value).
                             *
                             * **Note:** Unlike `_.pullAllBy`, this method returns a new array.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @param {...Array} [values] The values to exclude.
                             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
                             * @returns {Array} Returns the new array of filtered values.
                             * @example
                             *
                             * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor);
                             * // => [1.2]
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
                             * // => [{ 'x': 2 }]
                             */
                            var differenceBy = baseRest(function (array, values) {
                                var iteratee = last(values);
                                if (isArrayLikeObject(iteratee)) {
                                    iteratee = undefined;
                                }
                                return isArrayLikeObject(array)
                                    ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2))
                                    : [];
                            });

                            /**
                             * This method is like `_.difference` except that it accepts `comparator`
                             * which is invoked to compare elements of `array` to `values`. The order and
                             * references of result values are determined by the first array. The comparator
                             * is invoked with two arguments: (arrVal, othVal).
                             *
                             * **Note:** Unlike `_.pullAllWith`, this method returns a new array.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @param {...Array} [values] The values to exclude.
                             * @param {Function} [comparator] The comparator invoked per element.
                             * @returns {Array} Returns the new array of filtered values.
                             * @example
                             *
                             * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
                             *
                             * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
                             * // => [{ 'x': 2, 'y': 1 }]
                             */
                            var differenceWith = baseRest(function (array, values) {
                                var comparator = last(values);
                                if (isArrayLikeObject(comparator)) {
                                    comparator = undefined;
                                }
                                return isArrayLikeObject(array)
                                    ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator)
                                    : [];
                            });

                            /**
                             * Creates a slice of `array` with `n` elements dropped from the beginning.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.5.0
                             * @category Array
                             * @param {Array} array The array to query.
                             * @param {number} [n=1] The number of elements to drop.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {Array} Returns the slice of `array`.
                             * @example
                             *
                             * _.drop([1, 2, 3]);
                             * // => [2, 3]
                             *
                             * _.drop([1, 2, 3], 2);
                             * // => [3]
                             *
                             * _.drop([1, 2, 3], 5);
                             * // => []
                             *
                             * _.drop([1, 2, 3], 0);
                             * // => [1, 2, 3]
                             */
                            function drop(array, n, guard) {
                                var length = array == null ? 0 : array.length;
                                if (!length) {
                                    return [];
                                }
                                n = (guard || n === undefined) ? 1 : toInteger(n);
                                return baseSlice(array, n < 0 ? 0 : n, length);
                            }

                            /**
                             * Creates a slice of `array` with `n` elements dropped from the end.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Array
                             * @param {Array} array The array to query.
                             * @param {number} [n=1] The number of elements to drop.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {Array} Returns the slice of `array`.
                             * @example
                             *
                             * _.dropRight([1, 2, 3]);
                             * // => [1, 2]
                             *
                             * _.dropRight([1, 2, 3], 2);
                             * // => [1]
                             *
                             * _.dropRight([1, 2, 3], 5);
                             * // => []
                             *
                             * _.dropRight([1, 2, 3], 0);
                             * // => [1, 2, 3]
                             */
                            function dropRight(array, n, guard) {
                                var length = array == null ? 0 : array.length;
                                if (!length) {
                                    return [];
                                }
                                n = (guard || n === undefined) ? 1 : toInteger(n);
                                n = length - n;
                                return baseSlice(array, 0, n < 0 ? 0 : n);
                            }

                            /**
                             * Creates a slice of `array` excluding elements dropped from the end.
                             * Elements are dropped until `predicate` returns falsey. The predicate is
                             * invoked with three arguments: (value, index, array).
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Array
                             * @param {Array} array The array to query.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @returns {Array} Returns the slice of `array`.
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'barney',  'active': true },
                             *   { 'user': 'fred',    'active': false },
                             *   { 'user': 'pebbles', 'active': false }
                             * ];
                             *
                             * _.dropRightWhile(users, function(o) { return !o.active; });
                             * // => objects for ['barney']
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false });
                             * // => objects for ['barney', 'fred']
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.dropRightWhile(users, ['active', false]);
                             * // => objects for ['barney']
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.dropRightWhile(users, 'active');
                             * // => objects for ['barney', 'fred', 'pebbles']
                             */
                            function dropRightWhile(array, predicate) {
                                return (array && array.length)
                                    ? baseWhile(array, getIteratee(predicate, 3), true, true)
                                    : [];
                            }

                            /**
                             * Creates a slice of `array` excluding elements dropped from the beginning.
                             * Elements are dropped until `predicate` returns falsey. The predicate is
                             * invoked with three arguments: (value, index, array).
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Array
                             * @param {Array} array The array to query.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @returns {Array} Returns the slice of `array`.
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'barney',  'active': false },
                             *   { 'user': 'fred',    'active': false },
                             *   { 'user': 'pebbles', 'active': true }
                             * ];
                             *
                             * _.dropWhile(users, function(o) { return !o.active; });
                             * // => objects for ['pebbles']
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.dropWhile(users, { 'user': 'barney', 'active': false });
                             * // => objects for ['fred', 'pebbles']
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.dropWhile(users, ['active', false]);
                             * // => objects for ['pebbles']
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.dropWhile(users, 'active');
                             * // => objects for ['barney', 'fred', 'pebbles']
                             */
                            function dropWhile(array, predicate) {
                                return (array && array.length)
                                    ? baseWhile(array, getIteratee(predicate, 3), true)
                                    : [];
                            }

                            /**
                             * Fills elements of `array` with `value` from `start` up to, but not
                             * including, `end`.
                             *
                             * **Note:** This method mutates `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.2.0
                             * @category Array
                             * @param {Array} array The array to fill.
                             * @param {*} value The value to fill `array` with.
                             * @param {number} [start=0] The start position.
                             * @param {number} [end=array.length] The end position.
                             * @returns {Array} Returns `array`.
                             * @example
                             *
                             * var array = [1, 2, 3];
                             *
                             * _.fill(array, 'a');
                             * console.log(array);
                             * // => ['a', 'a', 'a']
                             *
                             * _.fill(Array(3), 2);
                             * // => [2, 2, 2]
                             *
                             * _.fill([4, 6, 8, 10], '*', 1, 3);
                             * // => [4, '*', '*', 10]
                             */
                            function fill(array, value, start, end) {
                                var length = array == null ? 0 : array.length;
                                if (!length) {
                                    return [];
                                }
                                if (start && typeof start != 'number' && isIterateeCall(array, value, start)) {
                                    start = 0;
                                    end = length;
                                }
                                return baseFill(array, value, start, end);
                            }

                            /**
                             * This method is like `_.find` except that it returns the index of the first
                             * element `predicate` returns truthy for instead of the element itself.
                             *
                             * @static
                             * @memberOf _
                             * @since 1.1.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @param {number} [fromIndex=0] The index to search from.
                             * @returns {number} Returns the index of the found element, else `-1`.
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'barney',  'active': false },
                             *   { 'user': 'fred',    'active': false },
                             *   { 'user': 'pebbles', 'active': true }
                             * ];
                             *
                             * _.findIndex(users, function(o) { return o.user == 'barney'; });
                             * // => 0
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.findIndex(users, { 'user': 'fred', 'active': false });
                             * // => 1
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.findIndex(users, ['active', false]);
                             * // => 0
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.findIndex(users, 'active');
                             * // => 2
                             */
                            function findIndex(array, predicate, fromIndex) {
                                var length = array == null ? 0 : array.length;
                                if (!length) {
                                    return -1;
                                }
                                var index = fromIndex == null ? 0 : toInteger(fromIndex);
                                if (index < 0) {
                                    index = nativeMax(length + index, 0);
                                }
                                return baseFindIndex(array, getIteratee(predicate, 3), index);
                            }

                            /**
                             * This method is like `_.findIndex` except that it iterates over elements
                             * of `collection` from right to left.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.0.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @param {number} [fromIndex=array.length-1] The index to search from.
                             * @returns {number} Returns the index of the found element, else `-1`.
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'barney',  'active': true },
                             *   { 'user': 'fred',    'active': false },
                             *   { 'user': 'pebbles', 'active': false }
                             * ];
                             *
                             * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; });
                             * // => 2
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.findLastIndex(users, { 'user': 'barney', 'active': true });
                             * // => 0
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.findLastIndex(users, ['active', false]);
                             * // => 2
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.findLastIndex(users, 'active');
                             * // => 0
                             */
                            function findLastIndex(array, predicate, fromIndex) {
                                var length = array == null ? 0 : array.length;
                                if (!length) {
                                    return -1;
                                }
                                var index = length - 1;
                                if (fromIndex !== undefined) {
                                    index = toInteger(fromIndex);
                                    index = fromIndex < 0
                                        ? nativeMax(length + index, 0)
                                        : nativeMin(index, length - 1);
                                }
                                return baseFindIndex(array, getIteratee(predicate, 3), index, true);
                            }

                            /**
                             * Flattens `array` a single level deep.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Array
                             * @param {Array} array The array to flatten.
                             * @returns {Array} Returns the new flattened array.
                             * @example
                             *
                             * _.flatten([1, [2, [3, [4]], 5]]);
                             * // => [1, 2, [3, [4]], 5]
                             */
                            function flatten(array) {
                                var length = array == null ? 0 : array.length;
                                return length ? baseFlatten(array, 1) : [];
                            }

                            /**
                             * Recursively flattens `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Array
                             * @param {Array} array The array to flatten.
                             * @returns {Array} Returns the new flattened array.
                             * @example
                             *
                             * _.flattenDeep([1, [2, [3, [4]], 5]]);
                             * // => [1, 2, 3, 4, 5]
                             */
                            function flattenDeep(array) {
                                var length = array == null ? 0 : array.length;
                                return length ? baseFlatten(array, INFINITY) : [];
                            }

                            /**
                             * Recursively flatten `array` up to `depth` times.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.4.0
                             * @category Array
                             * @param {Array} array The array to flatten.
                             * @param {number} [depth=1] The maximum recursion depth.
                             * @returns {Array} Returns the new flattened array.
                             * @example
                             *
                             * var array = [1, [2, [3, [4]], 5]];
                             *
                             * _.flattenDepth(array, 1);
                             * // => [1, 2, [3, [4]], 5]
                             *
                             * _.flattenDepth(array, 2);
                             * // => [1, 2, 3, [4], 5]
                             */
                            function flattenDepth(array, depth) {
                                var length = array == null ? 0 : array.length;
                                if (!length) {
                                    return [];
                                }
                                depth = depth === undefined ? 1 : toInteger(depth);
                                return baseFlatten(array, depth);
                            }

                            /**
                             * The inverse of `_.toPairs`; this method returns an object composed
                             * from key-value `pairs`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} pairs The key-value pairs.
                             * @returns {Object} Returns the new object.
                             * @example
                             *
                             * _.fromPairs([['a', 1], ['b', 2]]);
                             * // => { 'a': 1, 'b': 2 }
                             */
                            function fromPairs(pairs) {
                                var index = -1,
                                    length = pairs == null ? 0 : pairs.length,
                                    result = {};

                                while (++index < length) {
                                    var pair = pairs[index];
                                    result[pair[0]] = pair[1];
                                }
                                return result;
                            }

                            /**
                             * Gets the first element of `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @alias first
                             * @category Array
                             * @param {Array} array The array to query.
                             * @returns {*} Returns the first element of `array`.
                             * @example
                             *
                             * _.head([1, 2, 3]);
                             * // => 1
                             *
                             * _.head([]);
                             * // => undefined
                             */
                            function head(array) {
                                return (array && array.length) ? array[0] : undefined;
                            }

                            /**
                             * Gets the index at which the first occurrence of `value` is found in `array`
                             * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
                             * for equality comparisons. If `fromIndex` is negative, it's used as the
                             * offset from the end of `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @param {*} value The value to search for.
                             * @param {number} [fromIndex=0] The index to search from.
                             * @returns {number} Returns the index of the matched value, else `-1`.
                             * @example
                             *
                             * _.indexOf([1, 2, 1, 2], 2);
                             * // => 1
                             *
                             * // Search from the `fromIndex`.
                             * _.indexOf([1, 2, 1, 2], 2, 2);
                             * // => 3
                             */
                            function indexOf(array, value, fromIndex) {
                                var length = array == null ? 0 : array.length;
                                if (!length) {
                                    return -1;
                                }
                                var index = fromIndex == null ? 0 : toInteger(fromIndex);
                                if (index < 0) {
                                    index = nativeMax(length + index, 0);
                                }
                                return baseIndexOf(array, value, index);
                            }

                            /**
                             * Gets all but the last element of `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Array
                             * @param {Array} array The array to query.
                             * @returns {Array} Returns the slice of `array`.
                             * @example
                             *
                             * _.initial([1, 2, 3]);
                             * // => [1, 2]
                             */
                            function initial(array) {
                                var length = array == null ? 0 : array.length;
                                return length ? baseSlice(array, 0, -1) : [];
                            }

                            /**
                             * Creates an array of unique values that are included in all given arrays
                             * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
                             * for equality comparisons. The order and references of result values are
                             * determined by the first array.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Array
                             * @param {...Array} [arrays] The arrays to inspect.
                             * @returns {Array} Returns the new array of intersecting values.
                             * @example
                             *
                             * _.intersection([2, 1], [2, 3]);
                             * // => [2]
                             */
                            var intersection = baseRest(function (arrays) {
                                var mapped = arrayMap(arrays, castArrayLikeObject);
                                return (mapped.length && mapped[0] === arrays[0])
                                    ? baseIntersection(mapped)
                                    : [];
                            });

                            /**
                             * This method is like `_.intersection` except that it accepts `iteratee`
                             * which is invoked for each element of each `arrays` to generate the criterion
                             * by which they're compared. The order and references of result values are
                             * determined by the first array. The iteratee is invoked with one argument:
                             * (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {...Array} [arrays] The arrays to inspect.
                             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
                             * @returns {Array} Returns the new array of intersecting values.
                             * @example
                             *
                             * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor);
                             * // => [2.1]
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
                             * // => [{ 'x': 1 }]
                             */
                            var intersectionBy = baseRest(function (arrays) {
                                var iteratee = last(arrays),
                                    mapped = arrayMap(arrays, castArrayLikeObject);

                                if (iteratee === last(mapped)) {
                                    iteratee = undefined;
                                } else {
                                    mapped.pop();
                                }
                                return (mapped.length && mapped[0] === arrays[0])
                                    ? baseIntersection(mapped, getIteratee(iteratee, 2))
                                    : [];
                            });

                            /**
                             * This method is like `_.intersection` except that it accepts `comparator`
                             * which is invoked to compare elements of `arrays`. The order and references
                             * of result values are determined by the first array. The comparator is
                             * invoked with two arguments: (arrVal, othVal).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {...Array} [arrays] The arrays to inspect.
                             * @param {Function} [comparator] The comparator invoked per element.
                             * @returns {Array} Returns the new array of intersecting values.
                             * @example
                             *
                             * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
                             * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
                             *
                             * _.intersectionWith(objects, others, _.isEqual);
                             * // => [{ 'x': 1, 'y': 2 }]
                             */
                            var intersectionWith = baseRest(function (arrays) {
                                var comparator = last(arrays),
                                    mapped = arrayMap(arrays, castArrayLikeObject);

                                comparator = typeof comparator == 'function' ? comparator : undefined;
                                if (comparator) {
                                    mapped.pop();
                                }
                                return (mapped.length && mapped[0] === arrays[0])
                                    ? baseIntersection(mapped, undefined, comparator)
                                    : [];
                            });

                            /**
                             * Converts all elements in `array` into a string separated by `separator`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The array to convert.
                             * @param {string} [separator=','] The element separator.
                             * @returns {string} Returns the joined string.
                             * @example
                             *
                             * _.join(['a', 'b', 'c'], '~');
                             * // => 'a~b~c'
                             */
                            function join(array, separator) {
                                return array == null ? '' : nativeJoin.call(array, separator);
                            }

                            /**
                             * Gets the last element of `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Array
                             * @param {Array} array The array to query.
                             * @returns {*} Returns the last element of `array`.
                             * @example
                             *
                             * _.last([1, 2, 3]);
                             * // => 3
                             */
                            function last(array) {
                                var length = array == null ? 0 : array.length;
                                return length ? array[length - 1] : undefined;
                            }

                            /**
                             * This method is like `_.indexOf` except that it iterates over elements of
                             * `array` from right to left.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @param {*} value The value to search for.
                             * @param {number} [fromIndex=array.length-1] The index to search from.
                             * @returns {number} Returns the index of the matched value, else `-1`.
                             * @example
                             *
                             * _.lastIndexOf([1, 2, 1, 2], 2);
                             * // => 3
                             *
                             * // Search from the `fromIndex`.
                             * _.lastIndexOf([1, 2, 1, 2], 2, 2);
                             * // => 1
                             */
                            function lastIndexOf(array, value, fromIndex) {
                                var length = array == null ? 0 : array.length;
                                if (!length) {
                                    return -1;
                                }
                                var index = length;
                                if (fromIndex !== undefined) {
                                    index = toInteger(fromIndex);
                                    index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);
                                }
                                return value === value
                                    ? strictLastIndexOf(array, value, index)
                                    : baseFindIndex(array, baseIsNaN, index, true);
                            }

                            /**
                             * Gets the element at index `n` of `array`. If `n` is negative, the nth
                             * element from the end is returned.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.11.0
                             * @category Array
                             * @param {Array} array The array to query.
                             * @param {number} [n=0] The index of the element to return.
                             * @returns {*} Returns the nth element of `array`.
                             * @example
                             *
                             * var array = ['a', 'b', 'c', 'd'];
                             *
                             * _.nth(array, 1);
                             * // => 'b'
                             *
                             * _.nth(array, -2);
                             * // => 'c';
                             */
                            function nth(array, n) {
                                return (array && array.length) ? baseNth(array, toInteger(n)) : undefined;
                            }

                            /**
                             * Removes all given values from `array` using
                             * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
                             * for equality comparisons.
                             *
                             * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove`
                             * to remove elements from an array by predicate.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.0.0
                             * @category Array
                             * @param {Array} array The array to modify.
                             * @param {...*} [values] The values to remove.
                             * @returns {Array} Returns `array`.
                             * @example
                             *
                             * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
                             *
                             * _.pull(array, 'a', 'c');
                             * console.log(array);
                             * // => ['b', 'b']
                             */
                            var pull = baseRest(pullAll);

                            /**
                             * This method is like `_.pull` except that it accepts an array of values to remove.
                             *
                             * **Note:** Unlike `_.difference`, this method mutates `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The array to modify.
                             * @param {Array} values The values to remove.
                             * @returns {Array} Returns `array`.
                             * @example
                             *
                             * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
                             *
                             * _.pullAll(array, ['a', 'c']);
                             * console.log(array);
                             * // => ['b', 'b']
                             */
                            function pullAll(array, values) {
                                return (array && array.length && values && values.length)
                                    ? basePullAll(array, values)
                                    : array;
                            }

                            /**
                             * This method is like `_.pullAll` except that it accepts `iteratee` which is
                             * invoked for each element of `array` and `values` to generate the criterion
                             * by which they're compared. The iteratee is invoked with one argument: (value).
                             *
                             * **Note:** Unlike `_.differenceBy`, this method mutates `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The array to modify.
                             * @param {Array} values The values to remove.
                             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
                             * @returns {Array} Returns `array`.
                             * @example
                             *
                             * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }];
                             *
                             * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x');
                             * console.log(array);
                             * // => [{ 'x': 2 }]
                             */
                            function pullAllBy(array, values, iteratee) {
                                return (array && array.length && values && values.length)
                                    ? basePullAll(array, values, getIteratee(iteratee, 2))
                                    : array;
                            }

                            /**
                             * This method is like `_.pullAll` except that it accepts `comparator` which
                             * is invoked to compare elements of `array` to `values`. The comparator is
                             * invoked with two arguments: (arrVal, othVal).
                             *
                             * **Note:** Unlike `_.differenceWith`, this method mutates `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.6.0
                             * @category Array
                             * @param {Array} array The array to modify.
                             * @param {Array} values The values to remove.
                             * @param {Function} [comparator] The comparator invoked per element.
                             * @returns {Array} Returns `array`.
                             * @example
                             *
                             * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
                             *
                             * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual);
                             * console.log(array);
                             * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
                             */
                            function pullAllWith(array, values, comparator) {
                                return (array && array.length && values && values.length)
                                    ? basePullAll(array, values, undefined, comparator)
                                    : array;
                            }

                            /**
                             * Removes elements from `array` corresponding to `indexes` and returns an
                             * array of removed elements.
                             *
                             * **Note:** Unlike `_.at`, this method mutates `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Array
                             * @param {Array} array The array to modify.
                             * @param {...(number|number[])} [indexes] The indexes of elements to remove.
                             * @returns {Array} Returns the new array of removed elements.
                             * @example
                             *
                             * var array = ['a', 'b', 'c', 'd'];
                             * var pulled = _.pullAt(array, [1, 3]);
                             *
                             * console.log(array);
                             * // => ['a', 'c']
                             *
                             * console.log(pulled);
                             * // => ['b', 'd']
                             */
                            var pullAt = flatRest(function (array, indexes) {
                                var length = array == null ? 0 : array.length,
                                    result = baseAt(array, indexes);

                                basePullAt(array, arrayMap(indexes, function (index) {
                                    return isIndex(index, length) ? +index : index;
                                }).sort(compareAscending));

                                return result;
                            });

                            /**
                             * Removes all elements from `array` that `predicate` returns truthy for
                             * and returns an array of the removed elements. The predicate is invoked
                             * with three arguments: (value, index, array).
                             *
                             * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull`
                             * to pull elements from an array by value.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.0.0
                             * @category Array
                             * @param {Array} array The array to modify.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @returns {Array} Returns the new array of removed elements.
                             * @example
                             *
                             * var array = [1, 2, 3, 4];
                             * var evens = _.remove(array, function(n) {
                             *   return n % 2 == 0;
                             * });
                             *
                             * console.log(array);
                             * // => [1, 3]
                             *
                             * console.log(evens);
                             * // => [2, 4]
                             */
                            function remove(array, predicate) {
                                var result = [];
                                if (!(array && array.length)) {
                                    return result;
                                }
                                var index = -1,
                                    indexes = [],
                                    length = array.length;

                                predicate = getIteratee(predicate, 3);
                                while (++index < length) {
                                    var value = array[index];
                                    if (predicate(value, index, array)) {
                                        result.push(value);
                                        indexes.push(index);
                                    }
                                }
                                basePullAt(array, indexes);
                                return result;
                            }

                            /**
                             * Reverses `array` so that the first element becomes the last, the second
                             * element becomes the second to last, and so on.
                             *
                             * **Note:** This method mutates `array` and is based on
                             * [`Array#reverse`](https://mdn.io/Array/reverse).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The array to modify.
                             * @returns {Array} Returns `array`.
                             * @example
                             *
                             * var array = [1, 2, 3];
                             *
                             * _.reverse(array);
                             * // => [3, 2, 1]
                             *
                             * console.log(array);
                             * // => [3, 2, 1]
                             */
                            function reverse(array) {
                                return array == null ? array : nativeReverse.call(array);
                            }

                            /**
                             * Creates a slice of `array` from `start` up to, but not including, `end`.
                             *
                             * **Note:** This method is used instead of
                             * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are
                             * returned.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Array
                             * @param {Array} array The array to slice.
                             * @param {number} [start=0] The start position.
                             * @param {number} [end=array.length] The end position.
                             * @returns {Array} Returns the slice of `array`.
                             */
                            function slice(array, start, end) {
                                var length = array == null ? 0 : array.length;
                                if (!length) {
                                    return [];
                                }
                                if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
                                    start = 0;
                                    end = length;
                                }
                                else {
                                    start = start == null ? 0 : toInteger(start);
                                    end = end === undefined ? length : toInteger(end);
                                }
                                return baseSlice(array, start, end);
                            }

                            /**
                             * Uses a binary search to determine the lowest index at which `value`
                             * should be inserted into `array` in order to maintain its sort order.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Array
                             * @param {Array} array The sorted array to inspect.
                             * @param {*} value The value to evaluate.
                             * @returns {number} Returns the index at which `value` should be inserted
                             *  into `array`.
                             * @example
                             *
                             * _.sortedIndex([30, 50], 40);
                             * // => 1
                             */
                            function sortedIndex(array, value) {
                                return baseSortedIndex(array, value);
                            }

                            /**
                             * This method is like `_.sortedIndex` except that it accepts `iteratee`
                             * which is invoked for `value` and each element of `array` to compute their
                             * sort ranking. The iteratee is invoked with one argument: (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The sorted array to inspect.
                             * @param {*} value The value to evaluate.
                             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
                             * @returns {number} Returns the index at which `value` should be inserted
                             *  into `array`.
                             * @example
                             *
                             * var objects = [{ 'x': 4 }, { 'x': 5 }];
                             *
                             * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
                             * // => 0
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.sortedIndexBy(objects, { 'x': 4 }, 'x');
                             * // => 0
                             */
                            function sortedIndexBy(array, value, iteratee) {
                                return baseSortedIndexBy(array, value, getIteratee(iteratee, 2));
                            }

                            /**
                             * This method is like `_.indexOf` except that it performs a binary
                             * search on a sorted `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @param {*} value The value to search for.
                             * @returns {number} Returns the index of the matched value, else `-1`.
                             * @example
                             *
                             * _.sortedIndexOf([4, 5, 5, 5, 6], 5);
                             * // => 1
                             */
                            function sortedIndexOf(array, value) {
                                var length = array == null ? 0 : array.length;
                                if (length) {
                                    var index = baseSortedIndex(array, value);
                                    if (index < length && eq(array[index], value)) {
                                        return index;
                                    }
                                }
                                return -1;
                            }

                            /**
                             * This method is like `_.sortedIndex` except that it returns the highest
                             * index at which `value` should be inserted into `array` in order to
                             * maintain its sort order.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Array
                             * @param {Array} array The sorted array to inspect.
                             * @param {*} value The value to evaluate.
                             * @returns {number} Returns the index at which `value` should be inserted
                             *  into `array`.
                             * @example
                             *
                             * _.sortedLastIndex([4, 5, 5, 5, 6], 5);
                             * // => 4
                             */
                            function sortedLastIndex(array, value) {
                                return baseSortedIndex(array, value, true);
                            }

                            /**
                             * This method is like `_.sortedLastIndex` except that it accepts `iteratee`
                             * which is invoked for `value` and each element of `array` to compute their
                             * sort ranking. The iteratee is invoked with one argument: (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The sorted array to inspect.
                             * @param {*} value The value to evaluate.
                             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
                             * @returns {number} Returns the index at which `value` should be inserted
                             *  into `array`.
                             * @example
                             *
                             * var objects = [{ 'x': 4 }, { 'x': 5 }];
                             *
                             * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
                             * // => 1
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x');
                             * // => 1
                             */
                            function sortedLastIndexBy(array, value, iteratee) {
                                return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true);
                            }

                            /**
                             * This method is like `_.lastIndexOf` except that it performs a binary
                             * search on a sorted `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @param {*} value The value to search for.
                             * @returns {number} Returns the index of the matched value, else `-1`.
                             * @example
                             *
                             * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5);
                             * // => 3
                             */
                            function sortedLastIndexOf(array, value) {
                                var length = array == null ? 0 : array.length;
                                if (length) {
                                    var index = baseSortedIndex(array, value, true) - 1;
                                    if (eq(array[index], value)) {
                                        return index;
                                    }
                                }
                                return -1;
                            }

                            /**
                             * This method is like `_.uniq` except that it's designed and optimized
                             * for sorted arrays.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @returns {Array} Returns the new duplicate free array.
                             * @example
                             *
                             * _.sortedUniq([1, 1, 2]);
                             * // => [1, 2]
                             */
                            function sortedUniq(array) {
                                return (array && array.length)
                                    ? baseSortedUniq(array)
                                    : [];
                            }

                            /**
                             * This method is like `_.uniqBy` except that it's designed and optimized
                             * for sorted arrays.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @param {Function} [iteratee] The iteratee invoked per element.
                             * @returns {Array} Returns the new duplicate free array.
                             * @example
                             *
                             * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
                             * // => [1.1, 2.3]
                             */
                            function sortedUniqBy(array, iteratee) {
                                return (array && array.length)
                                    ? baseSortedUniq(array, getIteratee(iteratee, 2))
                                    : [];
                            }

                            /**
                             * Gets all but the first element of `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The array to query.
                             * @returns {Array} Returns the slice of `array`.
                             * @example
                             *
                             * _.tail([1, 2, 3]);
                             * // => [2, 3]
                             */
                            function tail(array) {
                                var length = array == null ? 0 : array.length;
                                return length ? baseSlice(array, 1, length) : [];
                            }

                            /**
                             * Creates a slice of `array` with `n` elements taken from the beginning.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Array
                             * @param {Array} array The array to query.
                             * @param {number} [n=1] The number of elements to take.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {Array} Returns the slice of `array`.
                             * @example
                             *
                             * _.take([1, 2, 3]);
                             * // => [1]
                             *
                             * _.take([1, 2, 3], 2);
                             * // => [1, 2]
                             *
                             * _.take([1, 2, 3], 5);
                             * // => [1, 2, 3]
                             *
                             * _.take([1, 2, 3], 0);
                             * // => []
                             */
                            function take(array, n, guard) {
                                if (!(array && array.length)) {
                                    return [];
                                }
                                n = (guard || n === undefined) ? 1 : toInteger(n);
                                return baseSlice(array, 0, n < 0 ? 0 : n);
                            }

                            /**
                             * Creates a slice of `array` with `n` elements taken from the end.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Array
                             * @param {Array} array The array to query.
                             * @param {number} [n=1] The number of elements to take.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {Array} Returns the slice of `array`.
                             * @example
                             *
                             * _.takeRight([1, 2, 3]);
                             * // => [3]
                             *
                             * _.takeRight([1, 2, 3], 2);
                             * // => [2, 3]
                             *
                             * _.takeRight([1, 2, 3], 5);
                             * // => [1, 2, 3]
                             *
                             * _.takeRight([1, 2, 3], 0);
                             * // => []
                             */
                            function takeRight(array, n, guard) {
                                var length = array == null ? 0 : array.length;
                                if (!length) {
                                    return [];
                                }
                                n = (guard || n === undefined) ? 1 : toInteger(n);
                                n = length - n;
                                return baseSlice(array, n < 0 ? 0 : n, length);
                            }

                            /**
                             * Creates a slice of `array` with elements taken from the end. Elements are
                             * taken until `predicate` returns falsey. The predicate is invoked with
                             * three arguments: (value, index, array).
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Array
                             * @param {Array} array The array to query.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @returns {Array} Returns the slice of `array`.
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'barney',  'active': true },
                             *   { 'user': 'fred',    'active': false },
                             *   { 'user': 'pebbles', 'active': false }
                             * ];
                             *
                             * _.takeRightWhile(users, function(o) { return !o.active; });
                             * // => objects for ['fred', 'pebbles']
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false });
                             * // => objects for ['pebbles']
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.takeRightWhile(users, ['active', false]);
                             * // => objects for ['fred', 'pebbles']
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.takeRightWhile(users, 'active');
                             * // => []
                             */
                            function takeRightWhile(array, predicate) {
                                return (array && array.length)
                                    ? baseWhile(array, getIteratee(predicate, 3), false, true)
                                    : [];
                            }

                            /**
                             * Creates a slice of `array` with elements taken from the beginning. Elements
                             * are taken until `predicate` returns falsey. The predicate is invoked with
                             * three arguments: (value, index, array).
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Array
                             * @param {Array} array The array to query.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @returns {Array} Returns the slice of `array`.
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'barney',  'active': false },
                             *   { 'user': 'fred',    'active': false },
                             *   { 'user': 'pebbles', 'active': true }
                             * ];
                             *
                             * _.takeWhile(users, function(o) { return !o.active; });
                             * // => objects for ['barney', 'fred']
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.takeWhile(users, { 'user': 'barney', 'active': false });
                             * // => objects for ['barney']
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.takeWhile(users, ['active', false]);
                             * // => objects for ['barney', 'fred']
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.takeWhile(users, 'active');
                             * // => []
                             */
                            function takeWhile(array, predicate) {
                                return (array && array.length)
                                    ? baseWhile(array, getIteratee(predicate, 3))
                                    : [];
                            }

                            /**
                             * Creates an array of unique values, in order, from all given arrays using
                             * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
                             * for equality comparisons.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Array
                             * @param {...Array} [arrays] The arrays to inspect.
                             * @returns {Array} Returns the new array of combined values.
                             * @example
                             *
                             * _.union([2], [1, 2]);
                             * // => [2, 1]
                             */
                            var union = baseRest(function (arrays) {
                                return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
                            });

                            /**
                             * This method is like `_.union` except that it accepts `iteratee` which is
                             * invoked for each element of each `arrays` to generate the criterion by
                             * which uniqueness is computed. Result values are chosen from the first
                             * array in which the value occurs. The iteratee is invoked with one argument:
                             * (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {...Array} [arrays] The arrays to inspect.
                             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
                             * @returns {Array} Returns the new array of combined values.
                             * @example
                             *
                             * _.unionBy([2.1], [1.2, 2.3], Math.floor);
                             * // => [2.1, 1.2]
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
                             * // => [{ 'x': 1 }, { 'x': 2 }]
                             */
                            var unionBy = baseRest(function (arrays) {
                                var iteratee = last(arrays);
                                if (isArrayLikeObject(iteratee)) {
                                    iteratee = undefined;
                                }
                                return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2));
                            });

                            /**
                             * This method is like `_.union` except that it accepts `comparator` which
                             * is invoked to compare elements of `arrays`. Result values are chosen from
                             * the first array in which the value occurs. The comparator is invoked
                             * with two arguments: (arrVal, othVal).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {...Array} [arrays] The arrays to inspect.
                             * @param {Function} [comparator] The comparator invoked per element.
                             * @returns {Array} Returns the new array of combined values.
                             * @example
                             *
                             * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
                             * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
                             *
                             * _.unionWith(objects, others, _.isEqual);
                             * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
                             */
                            var unionWith = baseRest(function (arrays) {
                                var comparator = last(arrays);
                                comparator = typeof comparator == 'function' ? comparator : undefined;
                                return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator);
                            });

                            /**
                             * Creates a duplicate-free version of an array, using
                             * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
                             * for equality comparisons, in which only the first occurrence of each element
                             * is kept. The order of result values is determined by the order they occur
                             * in the array.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @returns {Array} Returns the new duplicate free array.
                             * @example
                             *
                             * _.uniq([2, 1, 2]);
                             * // => [2, 1]
                             */
                            function uniq(array) {
                                return (array && array.length) ? baseUniq(array) : [];
                            }

                            /**
                             * This method is like `_.uniq` except that it accepts `iteratee` which is
                             * invoked for each element in `array` to generate the criterion by which
                             * uniqueness is computed. The order of result values is determined by the
                             * order they occur in the array. The iteratee is invoked with one argument:
                             * (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
                             * @returns {Array} Returns the new duplicate free array.
                             * @example
                             *
                             * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
                             * // => [2.1, 1.2]
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
                             * // => [{ 'x': 1 }, { 'x': 2 }]
                             */
                            function uniqBy(array, iteratee) {
                                return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : [];
                            }

                            /**
                             * This method is like `_.uniq` except that it accepts `comparator` which
                             * is invoked to compare elements of `array`. The order of result values is
                             * determined by the order they occur in the array.The comparator is invoked
                             * with two arguments: (arrVal, othVal).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @param {Function} [comparator] The comparator invoked per element.
                             * @returns {Array} Returns the new duplicate free array.
                             * @example
                             *
                             * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
                             *
                             * _.uniqWith(objects, _.isEqual);
                             * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
                             */
                            function uniqWith(array, comparator) {
                                comparator = typeof comparator == 'function' ? comparator : undefined;
                                return (array && array.length) ? baseUniq(array, undefined, comparator) : [];
                            }

                            /**
                             * This method is like `_.zip` except that it accepts an array of grouped
                             * elements and creates an array regrouping the elements to their pre-zip
                             * configuration.
                             *
                             * @static
                             * @memberOf _
                             * @since 1.2.0
                             * @category Array
                             * @param {Array} array The array of grouped elements to process.
                             * @returns {Array} Returns the new array of regrouped elements.
                             * @example
                             *
                             * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]);
                             * // => [['a', 1, true], ['b', 2, false]]
                             *
                             * _.unzip(zipped);
                             * // => [['a', 'b'], [1, 2], [true, false]]
                             */
                            function unzip(array) {
                                if (!(array && array.length)) {
                                    return [];
                                }
                                var length = 0;
                                array = arrayFilter(array, function (group) {
                                    if (isArrayLikeObject(group)) {
                                        length = nativeMax(group.length, length);
                                        return true;
                                    }
                                });
                                return baseTimes(length, function (index) {
                                    return arrayMap(array, baseProperty(index));
                                });
                            }

                            /**
                             * This method is like `_.unzip` except that it accepts `iteratee` to specify
                             * how regrouped values should be combined. The iteratee is invoked with the
                             * elements of each group: (...group).
                             *
                             * @static
                             * @memberOf _
                             * @since 3.8.0
                             * @category Array
                             * @param {Array} array The array of grouped elements to process.
                             * @param {Function} [iteratee=_.identity] The function to combine
                             *  regrouped values.
                             * @returns {Array} Returns the new array of regrouped elements.
                             * @example
                             *
                             * var zipped = _.zip([1, 2], [10, 20], [100, 200]);
                             * // => [[1, 10, 100], [2, 20, 200]]
                             *
                             * _.unzipWith(zipped, _.add);
                             * // => [3, 30, 300]
                             */
                            function unzipWith(array, iteratee) {
                                if (!(array && array.length)) {
                                    return [];
                                }
                                var result = unzip(array);
                                if (iteratee == null) {
                                    return result;
                                }
                                return arrayMap(result, function (group) {
                                    return apply(iteratee, undefined, group);
                                });
                            }

                            /**
                             * Creates an array excluding all given values using
                             * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
                             * for equality comparisons.
                             *
                             * **Note:** Unlike `_.pull`, this method returns a new array.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Array
                             * @param {Array} array The array to inspect.
                             * @param {...*} [values] The values to exclude.
                             * @returns {Array} Returns the new array of filtered values.
                             * @see _.difference, _.xor
                             * @example
                             *
                             * _.without([2, 1, 2, 3], 1, 2);
                             * // => [3]
                             */
                            var without = baseRest(function (array, values) {
                                return isArrayLikeObject(array)
                                    ? baseDifference(array, values)
                                    : [];
                            });

                            /**
                             * Creates an array of unique values that is the
                             * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference)
                             * of the given arrays. The order of result values is determined by the order
                             * they occur in the arrays.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.4.0
                             * @category Array
                             * @param {...Array} [arrays] The arrays to inspect.
                             * @returns {Array} Returns the new array of filtered values.
                             * @see _.difference, _.without
                             * @example
                             *
                             * _.xor([2, 1], [2, 3]);
                             * // => [1, 3]
                             */
                            var xor = baseRest(function (arrays) {
                                return baseXor(arrayFilter(arrays, isArrayLikeObject));
                            });

                            /**
                             * This method is like `_.xor` except that it accepts `iteratee` which is
                             * invoked for each element of each `arrays` to generate the criterion by
                             * which by which they're compared. The order of result values is determined
                             * by the order they occur in the arrays. The iteratee is invoked with one
                             * argument: (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {...Array} [arrays] The arrays to inspect.
                             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
                             * @returns {Array} Returns the new array of filtered values.
                             * @example
                             *
                             * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
                             * // => [1.2, 3.4]
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
                             * // => [{ 'x': 2 }]
                             */
                            var xorBy = baseRest(function (arrays) {
                                var iteratee = last(arrays);
                                if (isArrayLikeObject(iteratee)) {
                                    iteratee = undefined;
                                }
                                return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2));
                            });

                            /**
                             * This method is like `_.xor` except that it accepts `comparator` which is
                             * invoked to compare elements of `arrays`. The order of result values is
                             * determined by the order they occur in the arrays. The comparator is invoked
                             * with two arguments: (arrVal, othVal).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Array
                             * @param {...Array} [arrays] The arrays to inspect.
                             * @param {Function} [comparator] The comparator invoked per element.
                             * @returns {Array} Returns the new array of filtered values.
                             * @example
                             *
                             * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
                             * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
                             *
                             * _.xorWith(objects, others, _.isEqual);
                             * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
                             */
                            var xorWith = baseRest(function (arrays) {
                                var comparator = last(arrays);
                                comparator = typeof comparator == 'function' ? comparator : undefined;
                                return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator);
                            });

                            /**
                             * Creates an array of grouped elements, the first of which contains the
                             * first elements of the given arrays, the second of which contains the
                             * second elements of the given arrays, and so on.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Array
                             * @param {...Array} [arrays] The arrays to process.
                             * @returns {Array} Returns the new array of grouped elements.
                             * @example
                             *
                             * _.zip(['a', 'b'], [1, 2], [true, false]);
                             * // => [['a', 1, true], ['b', 2, false]]
                             */
                            var zip = baseRest(unzip);

                            /**
                             * This method is like `_.fromPairs` except that it accepts two arrays,
                             * one of property identifiers and one of corresponding values.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.4.0
                             * @category Array
                             * @param {Array} [props=[]] The property identifiers.
                             * @param {Array} [values=[]] The property values.
                             * @returns {Object} Returns the new object.
                             * @example
                             *
                             * _.zipObject(['a', 'b'], [1, 2]);
                             * // => { 'a': 1, 'b': 2 }
                             */
                            function zipObject(props, values) {
                                return baseZipObject(props || [], values || [], assignValue);
                            }

                            /**
                             * This method is like `_.zipObject` except that it supports property paths.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.1.0
                             * @category Array
                             * @param {Array} [props=[]] The property identifiers.
                             * @param {Array} [values=[]] The property values.
                             * @returns {Object} Returns the new object.
                             * @example
                             *
                             * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
                             * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
                             */
                            function zipObjectDeep(props, values) {
                                return baseZipObject(props || [], values || [], baseSet);
                            }

                            /**
                             * This method is like `_.zip` except that it accepts `iteratee` to specify
                             * how grouped values should be combined. The iteratee is invoked with the
                             * elements of each group: (...group).
                             *
                             * @static
                             * @memberOf _
                             * @since 3.8.0
                             * @category Array
                             * @param {...Array} [arrays] The arrays to process.
                             * @param {Function} [iteratee=_.identity] The function to combine
                             *  grouped values.
                             * @returns {Array} Returns the new array of grouped elements.
                             * @example
                             *
                             * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
                             *   return a + b + c;
                             * });
                             * // => [111, 222]
                             */
                            var zipWith = baseRest(function (arrays) {
                                var length = arrays.length,
                                    iteratee = length > 1 ? arrays[length - 1] : undefined;

                                iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined;
                                return unzipWith(arrays, iteratee);
                            });

                            /*------------------------------------------------------------------------*/

                            /**
                             * Creates a `lodash` wrapper instance that wraps `value` with explicit method
                             * chain sequences enabled. The result of such sequences must be unwrapped
                             * with `_#value`.
                             *
                             * @static
                             * @memberOf _
                             * @since 1.3.0
                             * @category Seq
                             * @param {*} value The value to wrap.
                             * @returns {Object} Returns the new `lodash` wrapper instance.
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'barney',  'age': 36 },
                             *   { 'user': 'fred',    'age': 40 },
                             *   { 'user': 'pebbles', 'age': 1 }
                             * ];
                             *
                             * var youngest = _
                             *   .chain(users)
                             *   .sortBy('age')
                             *   .map(function(o) {
                             *     return o.user + ' is ' + o.age;
                             *   })
                             *   .head()
                             *   .value();
                             * // => 'pebbles is 1'
                             */
                            function chain(value) {
                                var result = lodash(value);
                                result.__chain__ = true;
                                return result;
                            }

                            /**
                             * This method invokes `interceptor` and returns `value`. The interceptor
                             * is invoked with one argument; (value). The purpose of this method is to
                             * "tap into" a method chain sequence in order to modify intermediate results.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Seq
                             * @param {*} value The value to provide to `interceptor`.
                             * @param {Function} interceptor The function to invoke.
                             * @returns {*} Returns `value`.
                             * @example
                             *
                             * _([1, 2, 3])
                             *  .tap(function(array) {
                             *    // Mutate input array.
                             *    array.pop();
                             *  })
                             *  .reverse()
                             *  .value();
                             * // => [2, 1]
                             */
                            function tap(value, interceptor) {
                                interceptor(value);
                                return value;
                            }

                            /**
                             * This method is like `_.tap` except that it returns the result of `interceptor`.
                             * The purpose of this method is to "pass thru" values replacing intermediate
                             * results in a method chain sequence.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Seq
                             * @param {*} value The value to provide to `interceptor`.
                             * @param {Function} interceptor The function to invoke.
                             * @returns {*} Returns the result of `interceptor`.
                             * @example
                             *
                             * _('  abc  ')
                             *  .chain()
                             *  .trim()
                             *  .thru(function(value) {
                             *    return [value];
                             *  })
                             *  .value();
                             * // => ['abc']
                             */
                            function thru(value, interceptor) {
                                return interceptor(value);
                            }

                            /**
                             * This method is the wrapper version of `_.at`.
                             *
                             * @name at
                             * @memberOf _
                             * @since 1.0.0
                             * @category Seq
                             * @param {...(string|string[])} [paths] The property paths to pick.
                             * @returns {Object} Returns the new `lodash` wrapper instance.
                             * @example
                             *
                             * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
                             *
                             * _(object).at(['a[0].b.c', 'a[1]']).value();
                             * // => [3, 4]
                             */
                            var wrapperAt = flatRest(function (paths) {
                                var length = paths.length,
                                    start = length ? paths[0] : 0,
                                    value = this.__wrapped__,
                                    interceptor = function (object) { return baseAt(object, paths); };

                                if (length > 1 || this.__actions__.length ||
                                    !(value instanceof LazyWrapper) || !isIndex(start)) {
                                    return this.thru(interceptor);
                                }
                                value = value.slice(start, +start + (length ? 1 : 0));
                                value.__actions__.push({
                                    'func': thru,
                                    'args': [interceptor],
                                    'thisArg': undefined
                                });
                                return new LodashWrapper(value, this.__chain__).thru(function (array) {
                                    if (length && !array.length) {
                                        array.push(undefined);
                                    }
                                    return array;
                                });
                            });

                            /**
                             * Creates a `lodash` wrapper instance with explicit method chain sequences enabled.
                             *
                             * @name chain
                             * @memberOf _
                             * @since 0.1.0
                             * @category Seq
                             * @returns {Object} Returns the new `lodash` wrapper instance.
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'barney', 'age': 36 },
                             *   { 'user': 'fred',   'age': 40 }
                             * ];
                             *
                             * // A sequence without explicit chaining.
                             * _(users).head();
                             * // => { 'user': 'barney', 'age': 36 }
                             *
                             * // A sequence with explicit chaining.
                             * _(users)
                             *   .chain()
                             *   .head()
                             *   .pick('user')
                             *   .value();
                             * // => { 'user': 'barney' }
                             */
                            function wrapperChain() {
                                return chain(this);
                            }

                            /**
                             * Executes the chain sequence and returns the wrapped result.
                             *
                             * @name commit
                             * @memberOf _
                             * @since 3.2.0
                             * @category Seq
                             * @returns {Object} Returns the new `lodash` wrapper instance.
                             * @example
                             *
                             * var array = [1, 2];
                             * var wrapped = _(array).push(3);
                             *
                             * console.log(array);
                             * // => [1, 2]
                             *
                             * wrapped = wrapped.commit();
                             * console.log(array);
                             * // => [1, 2, 3]
                             *
                             * wrapped.last();
                             * // => 3
                             *
                             * console.log(array);
                             * // => [1, 2, 3]
                             */
                            function wrapperCommit() {
                                return new LodashWrapper(this.value(), this.__chain__);
                            }

                            /**
                             * Gets the next value on a wrapped object following the
                             * [iterator protocol](https://mdn.io/iteration_protocols#iterator).
                             *
                             * @name next
                             * @memberOf _
                             * @since 4.0.0
                             * @category Seq
                             * @returns {Object} Returns the next iterator value.
                             * @example
                             *
                             * var wrapped = _([1, 2]);
                             *
                             * wrapped.next();
                             * // => { 'done': false, 'value': 1 }
                             *
                             * wrapped.next();
                             * // => { 'done': false, 'value': 2 }
                             *
                             * wrapped.next();
                             * // => { 'done': true, 'value': undefined }
                             */
                            function wrapperNext() {
                                if (this.__values__ === undefined) {
                                    this.__values__ = toArray(this.value());
                                }
                                var done = this.__index__ >= this.__values__.length,
                                    value = done ? undefined : this.__values__[this.__index__++];

                                return { 'done': done, 'value': value };
                            }

                            /**
                             * Enables the wrapper to be iterable.
                             *
                             * @name Symbol.iterator
                             * @memberOf _
                             * @since 4.0.0
                             * @category Seq
                             * @returns {Object} Returns the wrapper object.
                             * @example
                             *
                             * var wrapped = _([1, 2]);
                             *
                             * wrapped[Symbol.iterator]() === wrapped;
                             * // => true
                             *
                             * Array.from(wrapped);
                             * // => [1, 2]
                             */
                            function wrapperToIterator() {
                                return this;
                            }

                            /**
                             * Creates a clone of the chain sequence planting `value` as the wrapped value.
                             *
                             * @name plant
                             * @memberOf _
                             * @since 3.2.0
                             * @category Seq
                             * @param {*} value The value to plant.
                             * @returns {Object} Returns the new `lodash` wrapper instance.
                             * @example
                             *
                             * function square(n) {
                             *   return n * n;
                             * }
                             *
                             * var wrapped = _([1, 2]).map(square);
                             * var other = wrapped.plant([3, 4]);
                             *
                             * other.value();
                             * // => [9, 16]
                             *
                             * wrapped.value();
                             * // => [1, 4]
                             */
                            function wrapperPlant(value) {
                                var result,
                                    parent = this;

                                while (parent instanceof baseLodash) {
                                    var clone = wrapperClone(parent);
                                    clone.__index__ = 0;
                                    clone.__values__ = undefined;
                                    if (result) {
                                        previous.__wrapped__ = clone;
                                    } else {
                                        result = clone;
                                    }
                                    var previous = clone;
                                    parent = parent.__wrapped__;
                                }
                                previous.__wrapped__ = value;
                                return result;
                            }

                            /**
                             * This method is the wrapper version of `_.reverse`.
                             *
                             * **Note:** This method mutates the wrapped array.
                             *
                             * @name reverse
                             * @memberOf _
                             * @since 0.1.0
                             * @category Seq
                             * @returns {Object} Returns the new `lodash` wrapper instance.
                             * @example
                             *
                             * var array = [1, 2, 3];
                             *
                             * _(array).reverse().value()
                             * // => [3, 2, 1]
                             *
                             * console.log(array);
                             * // => [3, 2, 1]
                             */
                            function wrapperReverse() {
                                var value = this.__wrapped__;
                                if (value instanceof LazyWrapper) {
                                    var wrapped = value;
                                    if (this.__actions__.length) {
                                        wrapped = new LazyWrapper(this);
                                    }
                                    wrapped = wrapped.reverse();
                                    wrapped.__actions__.push({
                                        'func': thru,
                                        'args': [reverse],
                                        'thisArg': undefined
                                    });
                                    return new LodashWrapper(wrapped, this.__chain__);
                                }
                                return this.thru(reverse);
                            }

                            /**
                             * Executes the chain sequence to resolve the unwrapped value.
                             *
                             * @name value
                             * @memberOf _
                             * @since 0.1.0
                             * @alias toJSON, valueOf
                             * @category Seq
                             * @returns {*} Returns the resolved unwrapped value.
                             * @example
                             *
                             * _([1, 2, 3]).value();
                             * // => [1, 2, 3]
                             */
                            function wrapperValue() {
                                return baseWrapperValue(this.__wrapped__, this.__actions__);
                            }

                            /*------------------------------------------------------------------------*/

                            /**
                             * Creates an object composed of keys generated from the results of running
                             * each element of `collection` thru `iteratee`. The corresponding value of
                             * each key is the number of times the key was returned by `iteratee`. The
                             * iteratee is invoked with one argument: (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 0.5.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
                             * @returns {Object} Returns the composed aggregate object.
                             * @example
                             *
                             * _.countBy([6.1, 4.2, 6.3], Math.floor);
                             * // => { '4': 1, '6': 2 }
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.countBy(['one', 'two', 'three'], 'length');
                             * // => { '3': 2, '5': 1 }
                             */
                            var countBy = createAggregator(function (result, value, key) {
                                if (hasOwnProperty.call(result, key)) {
                                    ++result[key];
                                } else {
                                    baseAssignValue(result, key, 1);
                                }
                            });

                            /**
                             * Checks if `predicate` returns truthy for **all** elements of `collection`.
                             * Iteration is stopped once `predicate` returns falsey. The predicate is
                             * invoked with three arguments: (value, index|key, collection).
                             *
                             * **Note:** This method returns `true` for
                             * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because
                             * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of
                             * elements of empty collections.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {boolean} Returns `true` if all elements pass the predicate check,
                             *  else `false`.
                             * @example
                             *
                             * _.every([true, 1, null, 'yes'], Boolean);
                             * // => false
                             *
                             * var users = [
                             *   { 'user': 'barney', 'age': 36, 'active': false },
                             *   { 'user': 'fred',   'age': 40, 'active': false }
                             * ];
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.every(users, { 'user': 'barney', 'active': false });
                             * // => false
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.every(users, ['active', false]);
                             * // => true
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.every(users, 'active');
                             * // => false
                             */
                            function every(collection, predicate, guard) {
                                var func = isArray(collection) ? arrayEvery : baseEvery;
                                if (guard && isIterateeCall(collection, predicate, guard)) {
                                    predicate = undefined;
                                }
                                return func(collection, getIteratee(predicate, 3));
                            }

                            /**
                             * Iterates over elements of `collection`, returning an array of all elements
                             * `predicate` returns truthy for. The predicate is invoked with three
                             * arguments: (value, index|key, collection).
                             *
                             * **Note:** Unlike `_.remove`, this method returns a new array.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @returns {Array} Returns the new filtered array.
                             * @see _.reject
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'barney', 'age': 36, 'active': true },
                             *   { 'user': 'fred',   'age': 40, 'active': false }
                             * ];
                             *
                             * _.filter(users, function(o) { return !o.active; });
                             * // => objects for ['fred']
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.filter(users, { 'age': 36, 'active': true });
                             * // => objects for ['barney']
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.filter(users, ['active', false]);
                             * // => objects for ['fred']
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.filter(users, 'active');
                             * // => objects for ['barney']
                             *
                             * // Combining several predicates using `_.overEvery` or `_.overSome`.
                             * _.filter(users, _.overSome([{ 'age': 36 }, ['age', 40]]));
                             * // => objects for ['fred', 'barney']
                             */
                            function filter(collection, predicate) {
                                var func = isArray(collection) ? arrayFilter : baseFilter;
                                return func(collection, getIteratee(predicate, 3));
                            }

                            /**
                             * Iterates over elements of `collection`, returning the first element
                             * `predicate` returns truthy for. The predicate is invoked with three
                             * arguments: (value, index|key, collection).
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to inspect.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @param {number} [fromIndex=0] The index to search from.
                             * @returns {*} Returns the matched element, else `undefined`.
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'barney',  'age': 36, 'active': true },
                             *   { 'user': 'fred',    'age': 40, 'active': false },
                             *   { 'user': 'pebbles', 'age': 1,  'active': true }
                             * ];
                             *
                             * _.find(users, function(o) { return o.age < 40; });
                             * // => object for 'barney'
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.find(users, { 'age': 1, 'active': true });
                             * // => object for 'pebbles'
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.find(users, ['active', false]);
                             * // => object for 'fred'
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.find(users, 'active');
                             * // => object for 'barney'
                             */
                            var find = createFind(findIndex);

                            /**
                             * This method is like `_.find` except that it iterates over elements of
                             * `collection` from right to left.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.0.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to inspect.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @param {number} [fromIndex=collection.length-1] The index to search from.
                             * @returns {*} Returns the matched element, else `undefined`.
                             * @example
                             *
                             * _.findLast([1, 2, 3, 4], function(n) {
                             *   return n % 2 == 1;
                             * });
                             * // => 3
                             */
                            var findLast = createFind(findLastIndex);

                            /**
                             * Creates a flattened array of values by running each element in `collection`
                             * thru `iteratee` and flattening the mapped results. The iteratee is invoked
                             * with three arguments: (value, index|key, collection).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @returns {Array} Returns the new flattened array.
                             * @example
                             *
                             * function duplicate(n) {
                             *   return [n, n];
                             * }
                             *
                             * _.flatMap([1, 2], duplicate);
                             * // => [1, 1, 2, 2]
                             */
                            function flatMap(collection, iteratee) {
                                return baseFlatten(map(collection, iteratee), 1);
                            }

                            /**
                             * This method is like `_.flatMap` except that it recursively flattens the
                             * mapped results.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.7.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @returns {Array} Returns the new flattened array.
                             * @example
                             *
                             * function duplicate(n) {
                             *   return [[[n, n]]];
                             * }
                             *
                             * _.flatMapDeep([1, 2], duplicate);
                             * // => [1, 1, 2, 2]
                             */
                            function flatMapDeep(collection, iteratee) {
                                return baseFlatten(map(collection, iteratee), INFINITY);
                            }

                            /**
                             * This method is like `_.flatMap` except that it recursively flattens the
                             * mapped results up to `depth` times.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.7.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @param {number} [depth=1] The maximum recursion depth.
                             * @returns {Array} Returns the new flattened array.
                             * @example
                             *
                             * function duplicate(n) {
                             *   return [[[n, n]]];
                             * }
                             *
                             * _.flatMapDepth([1, 2], duplicate, 2);
                             * // => [[1, 1], [2, 2]]
                             */
                            function flatMapDepth(collection, iteratee, depth) {
                                depth = depth === undefined ? 1 : toInteger(depth);
                                return baseFlatten(map(collection, iteratee), depth);
                            }

                            /**
                             * Iterates over elements of `collection` and invokes `iteratee` for each element.
                             * The iteratee is invoked with three arguments: (value, index|key, collection).
                             * Iteratee functions may exit iteration early by explicitly returning `false`.
                             *
                             * **Note:** As with other "Collections" methods, objects with a "length"
                             * property are iterated like arrays. To avoid this behavior use `_.forIn`
                             * or `_.forOwn` for object iteration.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @alias each
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @returns {Array|Object} Returns `collection`.
                             * @see _.forEachRight
                             * @example
                             *
                             * _.forEach([1, 2], function(value) {
                             *   console.log(value);
                             * });
                             * // => Logs `1` then `2`.
                             *
                             * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
                             *   console.log(key);
                             * });
                             * // => Logs 'a' then 'b' (iteration order is not guaranteed).
                             */
                            function forEach(collection, iteratee) {
                                var func = isArray(collection) ? arrayEach : baseEach;
                                return func(collection, getIteratee(iteratee, 3));
                            }

                            /**
                             * This method is like `_.forEach` except that it iterates over elements of
                             * `collection` from right to left.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.0.0
                             * @alias eachRight
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @returns {Array|Object} Returns `collection`.
                             * @see _.forEach
                             * @example
                             *
                             * _.forEachRight([1, 2], function(value) {
                             *   console.log(value);
                             * });
                             * // => Logs `2` then `1`.
                             */
                            function forEachRight(collection, iteratee) {
                                var func = isArray(collection) ? arrayEachRight : baseEachRight;
                                return func(collection, getIteratee(iteratee, 3));
                            }

                            /**
                             * Creates an object composed of keys generated from the results of running
                             * each element of `collection` thru `iteratee`. The order of grouped values
                             * is determined by the order they occur in `collection`. The corresponding
                             * value of each key is an array of elements responsible for generating the
                             * key. The iteratee is invoked with one argument: (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
                             * @returns {Object} Returns the composed aggregate object.
                             * @example
                             *
                             * _.groupBy([6.1, 4.2, 6.3], Math.floor);
                             * // => { '4': [4.2], '6': [6.1, 6.3] }
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.groupBy(['one', 'two', 'three'], 'length');
                             * // => { '3': ['one', 'two'], '5': ['three'] }
                             */
                            var groupBy = createAggregator(function (result, value, key) {
                                if (hasOwnProperty.call(result, key)) {
                                    result[key].push(value);
                                } else {
                                    baseAssignValue(result, key, [value]);
                                }
                            });

                            /**
                             * Checks if `value` is in `collection`. If `collection` is a string, it's
                             * checked for a substring of `value`, otherwise
                             * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
                             * is used for equality comparisons. If `fromIndex` is negative, it's used as
                             * the offset from the end of `collection`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Collection
                             * @param {Array|Object|string} collection The collection to inspect.
                             * @param {*} value The value to search for.
                             * @param {number} [fromIndex=0] The index to search from.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
                             * @returns {boolean} Returns `true` if `value` is found, else `false`.
                             * @example
                             *
                             * _.includes([1, 2, 3], 1);
                             * // => true
                             *
                             * _.includes([1, 2, 3], 1, 2);
                             * // => false
                             *
                             * _.includes({ 'a': 1, 'b': 2 }, 1);
                             * // => true
                             *
                             * _.includes('abcd', 'bc');
                             * // => true
                             */
                            function includes(collection, value, fromIndex, guard) {
                                collection = isArrayLike(collection) ? collection : values(collection);
                                fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0;

                                var length = collection.length;
                                if (fromIndex < 0) {
                                    fromIndex = nativeMax(length + fromIndex, 0);
                                }
                                return isString(collection)
                                    ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1)
                                    : (!!length && baseIndexOf(collection, value, fromIndex) > -1);
                            }

                            /**
                             * Invokes the method at `path` of each element in `collection`, returning
                             * an array of the results of each invoked method. Any additional arguments
                             * are provided to each invoked method. If `path` is a function, it's invoked
                             * for, and `this` bound to, each element in `collection`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Array|Function|string} path The path of the method to invoke or
                             *  the function invoked per iteration.
                             * @param {...*} [args] The arguments to invoke each method with.
                             * @returns {Array} Returns the array of results.
                             * @example
                             *
                             * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort');
                             * // => [[1, 5, 7], [1, 2, 3]]
                             *
                             * _.invokeMap([123, 456], String.prototype.split, '');
                             * // => [['1', '2', '3'], ['4', '5', '6']]
                             */
                            var invokeMap = baseRest(function (collection, path, args) {
                                var index = -1,
                                    isFunc = typeof path == 'function',
                                    result = isArrayLike(collection) ? Array(collection.length) : [];

                                baseEach(collection, function (value) {
                                    result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args);
                                });
                                return result;
                            });

                            /**
                             * Creates an object composed of keys generated from the results of running
                             * each element of `collection` thru `iteratee`. The corresponding value of
                             * each key is the last element responsible for generating the key. The
                             * iteratee is invoked with one argument: (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
                             * @returns {Object} Returns the composed aggregate object.
                             * @example
                             *
                             * var array = [
                             *   { 'dir': 'left', 'code': 97 },
                             *   { 'dir': 'right', 'code': 100 }
                             * ];
                             *
                             * _.keyBy(array, function(o) {
                             *   return String.fromCharCode(o.code);
                             * });
                             * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
                             *
                             * _.keyBy(array, 'dir');
                             * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
                             */
                            var keyBy = createAggregator(function (result, value, key) {
                                baseAssignValue(result, key, value);
                            });

                            /**
                             * Creates an array of values by running each element in `collection` thru
                             * `iteratee`. The iteratee is invoked with three arguments:
                             * (value, index|key, collection).
                             *
                             * Many lodash methods are guarded to work as iteratees for methods like
                             * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
                             *
                             * The guarded methods are:
                             * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`,
                             * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`,
                             * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`,
                             * `template`, `trim`, `trimEnd`, `trimStart`, and `words`
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @returns {Array} Returns the new mapped array.
                             * @example
                             *
                             * function square(n) {
                             *   return n * n;
                             * }
                             *
                             * _.map([4, 8], square);
                             * // => [16, 64]
                             *
                             * _.map({ 'a': 4, 'b': 8 }, square);
                             * // => [16, 64] (iteration order is not guaranteed)
                             *
                             * var users = [
                             *   { 'user': 'barney' },
                             *   { 'user': 'fred' }
                             * ];
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.map(users, 'user');
                             * // => ['barney', 'fred']
                             */
                            function map(collection, iteratee) {
                                var func = isArray(collection) ? arrayMap : baseMap;
                                return func(collection, getIteratee(iteratee, 3));
                            }

                            /**
                             * This method is like `_.sortBy` except that it allows specifying the sort
                             * orders of the iteratees to sort by. If `orders` is unspecified, all values
                             * are sorted in ascending order. Otherwise, specify an order of "desc" for
                             * descending or "asc" for ascending sort order of corresponding values.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]]
                             *  The iteratees to sort by.
                             * @param {string[]} [orders] The sort orders of `iteratees`.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
                             * @returns {Array} Returns the new sorted array.
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'fred',   'age': 48 },
                             *   { 'user': 'barney', 'age': 34 },
                             *   { 'user': 'fred',   'age': 40 },
                             *   { 'user': 'barney', 'age': 36 }
                             * ];
                             *
                             * // Sort by `user` in ascending order and by `age` in descending order.
                             * _.orderBy(users, ['user', 'age'], ['asc', 'desc']);
                             * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
                             */
                            function orderBy(collection, iteratees, orders, guard) {
                                if (collection == null) {
                                    return [];
                                }
                                if (!isArray(iteratees)) {
                                    iteratees = iteratees == null ? [] : [iteratees];
                                }
                                orders = guard ? undefined : orders;
                                if (!isArray(orders)) {
                                    orders = orders == null ? [] : [orders];
                                }
                                return baseOrderBy(collection, iteratees, orders);
                            }

                            /**
                             * Creates an array of elements split into two groups, the first of which
                             * contains elements `predicate` returns truthy for, the second of which
                             * contains elements `predicate` returns falsey for. The predicate is
                             * invoked with one argument: (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @returns {Array} Returns the array of grouped elements.
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'barney',  'age': 36, 'active': false },
                             *   { 'user': 'fred',    'age': 40, 'active': true },
                             *   { 'user': 'pebbles', 'age': 1,  'active': false }
                             * ];
                             *
                             * _.partition(users, function(o) { return o.active; });
                             * // => objects for [['fred'], ['barney', 'pebbles']]
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.partition(users, { 'age': 1, 'active': false });
                             * // => objects for [['pebbles'], ['barney', 'fred']]
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.partition(users, ['active', false]);
                             * // => objects for [['barney', 'pebbles'], ['fred']]
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.partition(users, 'active');
                             * // => objects for [['fred'], ['barney', 'pebbles']]
                             */
                            var partition = createAggregator(function (result, value, key) {
                                result[key ? 0 : 1].push(value);
                            }, function () { return [[], []]; });

                            /**
                             * Reduces `collection` to a value which is the accumulated result of running
                             * each element in `collection` thru `iteratee`, where each successive
                             * invocation is supplied the return value of the previous. If `accumulator`
                             * is not given, the first element of `collection` is used as the initial
                             * value. The iteratee is invoked with four arguments:
                             * (accumulator, value, index|key, collection).
                             *
                             * Many lodash methods are guarded to work as iteratees for methods like
                             * `_.reduce`, `_.reduceRight`, and `_.transform`.
                             *
                             * The guarded methods are:
                             * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`,
                             * and `sortBy`
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @param {*} [accumulator] The initial value.
                             * @returns {*} Returns the accumulated value.
                             * @see _.reduceRight
                             * @example
                             *
                             * _.reduce([1, 2], function(sum, n) {
                             *   return sum + n;
                             * }, 0);
                             * // => 3
                             *
                             * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
                             *   (result[value] || (result[value] = [])).push(key);
                             *   return result;
                             * }, {});
                             * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
                             */
                            function reduce(collection, iteratee, accumulator) {
                                var func = isArray(collection) ? arrayReduce : baseReduce,
                                    initAccum = arguments.length < 3;

                                return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach);
                            }

                            /**
                             * This method is like `_.reduce` except that it iterates over elements of
                             * `collection` from right to left.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @param {*} [accumulator] The initial value.
                             * @returns {*} Returns the accumulated value.
                             * @see _.reduce
                             * @example
                             *
                             * var array = [[0, 1], [2, 3], [4, 5]];
                             *
                             * _.reduceRight(array, function(flattened, other) {
                             *   return flattened.concat(other);
                             * }, []);
                             * // => [4, 5, 2, 3, 0, 1]
                             */
                            function reduceRight(collection, iteratee, accumulator) {
                                var func = isArray(collection) ? arrayReduceRight : baseReduce,
                                    initAccum = arguments.length < 3;

                                return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight);
                            }

                            /**
                             * The opposite of `_.filter`; this method returns the elements of `collection`
                             * that `predicate` does **not** return truthy for.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @returns {Array} Returns the new filtered array.
                             * @see _.filter
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'barney', 'age': 36, 'active': false },
                             *   { 'user': 'fred',   'age': 40, 'active': true }
                             * ];
                             *
                             * _.reject(users, function(o) { return !o.active; });
                             * // => objects for ['fred']
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.reject(users, { 'age': 40, 'active': true });
                             * // => objects for ['barney']
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.reject(users, ['active', false]);
                             * // => objects for ['fred']
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.reject(users, 'active');
                             * // => objects for ['barney']
                             */
                            function reject(collection, predicate) {
                                var func = isArray(collection) ? arrayFilter : baseFilter;
                                return func(collection, negate(getIteratee(predicate, 3)));
                            }

                            /**
                             * Gets a random element from `collection`.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.0.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to sample.
                             * @returns {*} Returns the random element.
                             * @example
                             *
                             * _.sample([1, 2, 3, 4]);
                             * // => 2
                             */
                            function sample(collection) {
                                var func = isArray(collection) ? arraySample : baseSample;
                                return func(collection);
                            }

                            /**
                             * Gets `n` random elements at unique keys from `collection` up to the
                             * size of `collection`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to sample.
                             * @param {number} [n=1] The number of elements to sample.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {Array} Returns the random elements.
                             * @example
                             *
                             * _.sampleSize([1, 2, 3], 2);
                             * // => [3, 1]
                             *
                             * _.sampleSize([1, 2, 3], 4);
                             * // => [2, 3, 1]
                             */
                            function sampleSize(collection, n, guard) {
                                if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) {
                                    n = 1;
                                } else {
                                    n = toInteger(n);
                                }
                                var func = isArray(collection) ? arraySampleSize : baseSampleSize;
                                return func(collection, n);
                            }

                            /**
                             * Creates an array of shuffled values, using a version of the
                             * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to shuffle.
                             * @returns {Array} Returns the new shuffled array.
                             * @example
                             *
                             * _.shuffle([1, 2, 3, 4]);
                             * // => [4, 1, 3, 2]
                             */
                            function shuffle(collection) {
                                var func = isArray(collection) ? arrayShuffle : baseShuffle;
                                return func(collection);
                            }

                            /**
                             * Gets the size of `collection` by returning its length for array-like
                             * values or the number of own enumerable string keyed properties for objects.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Collection
                             * @param {Array|Object|string} collection The collection to inspect.
                             * @returns {number} Returns the collection size.
                             * @example
                             *
                             * _.size([1, 2, 3]);
                             * // => 3
                             *
                             * _.size({ 'a': 1, 'b': 2 });
                             * // => 2
                             *
                             * _.size('pebbles');
                             * // => 7
                             */
                            function size(collection) {
                                if (collection == null) {
                                    return 0;
                                }
                                if (isArrayLike(collection)) {
                                    return isString(collection) ? stringSize(collection) : collection.length;
                                }
                                var tag = getTag(collection);
                                if (tag == mapTag || tag == setTag) {
                                    return collection.size;
                                }
                                return baseKeys(collection).length;
                            }

                            /**
                             * Checks if `predicate` returns truthy for **any** element of `collection`.
                             * Iteration is stopped once `predicate` returns truthy. The predicate is
                             * invoked with three arguments: (value, index|key, collection).
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {boolean} Returns `true` if any element passes the predicate check,
                             *  else `false`.
                             * @example
                             *
                             * _.some([null, 0, 'yes', false], Boolean);
                             * // => true
                             *
                             * var users = [
                             *   { 'user': 'barney', 'active': true },
                             *   { 'user': 'fred',   'active': false }
                             * ];
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.some(users, { 'user': 'barney', 'active': false });
                             * // => false
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.some(users, ['active', false]);
                             * // => true
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.some(users, 'active');
                             * // => true
                             */
                            function some(collection, predicate, guard) {
                                var func = isArray(collection) ? arraySome : baseSome;
                                if (guard && isIterateeCall(collection, predicate, guard)) {
                                    predicate = undefined;
                                }
                                return func(collection, getIteratee(predicate, 3));
                            }

                            /**
                             * Creates an array of elements, sorted in ascending order by the results of
                             * running each element in a collection thru each iteratee. This method
                             * performs a stable sort, that is, it preserves the original sort order of
                             * equal elements. The iteratees are invoked with one argument: (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Collection
                             * @param {Array|Object} collection The collection to iterate over.
                             * @param {...(Function|Function[])} [iteratees=[_.identity]]
                             *  The iteratees to sort by.
                             * @returns {Array} Returns the new sorted array.
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'fred',   'age': 48 },
                             *   { 'user': 'barney', 'age': 36 },
                             *   { 'user': 'fred',   'age': 30 },
                             *   { 'user': 'barney', 'age': 34 }
                             * ];
                             *
                             * _.sortBy(users, [function(o) { return o.user; }]);
                             * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 30]]
                             *
                             * _.sortBy(users, ['user', 'age']);
                             * // => objects for [['barney', 34], ['barney', 36], ['fred', 30], ['fred', 48]]
                             */
                            var sortBy = baseRest(function (collection, iteratees) {
                                if (collection == null) {
                                    return [];
                                }
                                var length = iteratees.length;
                                if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {
                                    iteratees = [];
                                } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {
                                    iteratees = [iteratees[0]];
                                }
                                return baseOrderBy(collection, baseFlatten(iteratees, 1), []);
                            });

                            /*------------------------------------------------------------------------*/

                            /**
                             * Gets the timestamp of the number of milliseconds that have elapsed since
                             * the Unix epoch (1 January 1970 00:00:00 UTC).
                             *
                             * @static
                             * @memberOf _
                             * @since 2.4.0
                             * @category Date
                             * @returns {number} Returns the timestamp.
                             * @example
                             *
                             * _.defer(function(stamp) {
                             *   console.log(_.now() - stamp);
                             * }, _.now());
                             * // => Logs the number of milliseconds it took for the deferred invocation.
                             */
                            var now = ctxNow || function () {
                                return root.Date.now();
                            };

                            /*------------------------------------------------------------------------*/

                            /**
                             * The opposite of `_.before`; this method creates a function that invokes
                             * `func` once it's called `n` or more times.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Function
                             * @param {number} n The number of calls before `func` is invoked.
                             * @param {Function} func The function to restrict.
                             * @returns {Function} Returns the new restricted function.
                             * @example
                             *
                             * var saves = ['profile', 'settings'];
                             *
                             * var done = _.after(saves.length, function() {
                             *   console.log('done saving!');
                             * });
                             *
                             * _.forEach(saves, function(type) {
                             *   asyncSave({ 'type': type, 'complete': done });
                             * });
                             * // => Logs 'done saving!' after the two async saves have completed.
                             */
                            function after(n, func) {
                                if (typeof func != 'function') {
                                    throw new TypeError(FUNC_ERROR_TEXT);
                                }
                                n = toInteger(n);
                                return function () {
                                    if (--n < 1) {
                                        return func.apply(this, arguments);
                                    }
                                };
                            }

                            /**
                             * Creates a function that invokes `func`, with up to `n` arguments,
                             * ignoring any additional arguments.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Function
                             * @param {Function} func The function to cap arguments for.
                             * @param {number} [n=func.length] The arity cap.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {Function} Returns the new capped function.
                             * @example
                             *
                             * _.map(['6', '8', '10'], _.ary(parseInt, 1));
                             * // => [6, 8, 10]
                             */
                            function ary(func, n, guard) {
                                n = guard ? undefined : n;
                                n = (func && n == null) ? func.length : n;
                                return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n);
                            }

                            /**
                             * Creates a function that invokes `func`, with the `this` binding and arguments
                             * of the created function, while it's called less than `n` times. Subsequent
                             * calls to the created function return the result of the last `func` invocation.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Function
                             * @param {number} n The number of calls at which `func` is no longer invoked.
                             * @param {Function} func The function to restrict.
                             * @returns {Function} Returns the new restricted function.
                             * @example
                             *
                             * jQuery(element).on('click', _.before(5, addContactToList));
                             * // => Allows adding up to 4 contacts to the list.
                             */
                            function before(n, func) {
                                var result;
                                if (typeof func != 'function') {
                                    throw new TypeError(FUNC_ERROR_TEXT);
                                }
                                n = toInteger(n);
                                return function () {
                                    if (--n > 0) {
                                        result = func.apply(this, arguments);
                                    }
                                    if (n <= 1) {
                                        func = undefined;
                                    }
                                    return result;
                                };
                            }

                            /**
                             * Creates a function that invokes `func` with the `this` binding of `thisArg`
                             * and `partials` prepended to the arguments it receives.
                             *
                             * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
                             * may be used as a placeholder for partially applied arguments.
                             *
                             * **Note:** Unlike native `Function#bind`, this method doesn't set the "length"
                             * property of bound functions.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Function
                             * @param {Function} func The function to bind.
                             * @param {*} thisArg The `this` binding of `func`.
                             * @param {...*} [partials] The arguments to be partially applied.
                             * @returns {Function} Returns the new bound function.
                             * @example
                             *
                             * function greet(greeting, punctuation) {
                             *   return greeting + ' ' + this.user + punctuation;
                             * }
                             *
                             * var object = { 'user': 'fred' };
                             *
                             * var bound = _.bind(greet, object, 'hi');
                             * bound('!');
                             * // => 'hi fred!'
                             *
                             * // Bound with placeholders.
                             * var bound = _.bind(greet, object, _, '!');
                             * bound('hi');
                             * // => 'hi fred!'
                             */
                            var bind = baseRest(function (func, thisArg, partials) {
                                var bitmask = WRAP_BIND_FLAG;
                                if (partials.length) {
                                    var holders = replaceHolders(partials, getHolder(bind));
                                    bitmask |= WRAP_PARTIAL_FLAG;
                                }
                                return createWrap(func, bitmask, thisArg, partials, holders);
                            });

                            /**
                             * Creates a function that invokes the method at `object[key]` with `partials`
                             * prepended to the arguments it receives.
                             *
                             * This method differs from `_.bind` by allowing bound functions to reference
                             * methods that may be redefined or don't yet exist. See
                             * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern)
                             * for more details.
                             *
                             * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
                             * builds, may be used as a placeholder for partially applied arguments.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.10.0
                             * @category Function
                             * @param {Object} object The object to invoke the method on.
                             * @param {string} key The key of the method.
                             * @param {...*} [partials] The arguments to be partially applied.
                             * @returns {Function} Returns the new bound function.
                             * @example
                             *
                             * var object = {
                             *   'user': 'fred',
                             *   'greet': function(greeting, punctuation) {
                             *     return greeting + ' ' + this.user + punctuation;
                             *   }
                             * };
                             *
                             * var bound = _.bindKey(object, 'greet', 'hi');
                             * bound('!');
                             * // => 'hi fred!'
                             *
                             * object.greet = function(greeting, punctuation) {
                             *   return greeting + 'ya ' + this.user + punctuation;
                             * };
                             *
                             * bound('!');
                             * // => 'hiya fred!'
                             *
                             * // Bound with placeholders.
                             * var bound = _.bindKey(object, 'greet', _, '!');
                             * bound('hi');
                             * // => 'hiya fred!'
                             */
                            var bindKey = baseRest(function (object, key, partials) {
                                var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG;
                                if (partials.length) {
                                    var holders = replaceHolders(partials, getHolder(bindKey));
                                    bitmask |= WRAP_PARTIAL_FLAG;
                                }
                                return createWrap(key, bitmask, object, partials, holders);
                            });

                            /**
                             * Creates a function that accepts arguments of `func` and either invokes
                             * `func` returning its result, if at least `arity` number of arguments have
                             * been provided, or returns a function that accepts the remaining `func`
                             * arguments, and so on. The arity of `func` may be specified if `func.length`
                             * is not sufficient.
                             *
                             * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
                             * may be used as a placeholder for provided arguments.
                             *
                             * **Note:** This method doesn't set the "length" property of curried functions.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.0.0
                             * @category Function
                             * @param {Function} func The function to curry.
                             * @param {number} [arity=func.length] The arity of `func`.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {Function} Returns the new curried function.
                             * @example
                             *
                             * var abc = function(a, b, c) {
                             *   return [a, b, c];
                             * };
                             *
                             * var curried = _.curry(abc);
                             *
                             * curried(1)(2)(3);
                             * // => [1, 2, 3]
                             *
                             * curried(1, 2)(3);
                             * // => [1, 2, 3]
                             *
                             * curried(1, 2, 3);
                             * // => [1, 2, 3]
                             *
                             * // Curried with placeholders.
                             * curried(1)(_, 3)(2);
                             * // => [1, 2, 3]
                             */
                            function curry(func, arity, guard) {
                                arity = guard ? undefined : arity;
                                var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
                                result.placeholder = curry.placeholder;
                                return result;
                            }

                            /**
                             * This method is like `_.curry` except that arguments are applied to `func`
                             * in the manner of `_.partialRight` instead of `_.partial`.
                             *
                             * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
                             * builds, may be used as a placeholder for provided arguments.
                             *
                             * **Note:** This method doesn't set the "length" property of curried functions.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Function
                             * @param {Function} func The function to curry.
                             * @param {number} [arity=func.length] The arity of `func`.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {Function} Returns the new curried function.
                             * @example
                             *
                             * var abc = function(a, b, c) {
                             *   return [a, b, c];
                             * };
                             *
                             * var curried = _.curryRight(abc);
                             *
                             * curried(3)(2)(1);
                             * // => [1, 2, 3]
                             *
                             * curried(2, 3)(1);
                             * // => [1, 2, 3]
                             *
                             * curried(1, 2, 3);
                             * // => [1, 2, 3]
                             *
                             * // Curried with placeholders.
                             * curried(3)(1, _)(2);
                             * // => [1, 2, 3]
                             */
                            function curryRight(func, arity, guard) {
                                arity = guard ? undefined : arity;
                                var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
                                result.placeholder = curryRight.placeholder;
                                return result;
                            }

                            /**
                             * Creates a debounced function that delays invoking `func` until after `wait`
                             * milliseconds have elapsed since the last time the debounced function was
                             * invoked. The debounced function comes with a `cancel` method to cancel
                             * delayed `func` invocations and a `flush` method to immediately invoke them.
                             * Provide `options` to indicate whether `func` should be invoked on the
                             * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
                             * with the last arguments provided to the debounced function. Subsequent
                             * calls to the debounced function return the result of the last `func`
                             * invocation.
                             *
                             * **Note:** If `leading` and `trailing` options are `true`, `func` is
                             * invoked on the trailing edge of the timeout only if the debounced function
                             * is invoked more than once during the `wait` timeout.
                             *
                             * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
                             * until to the next tick, similar to `setTimeout` with a timeout of `0`.
                             *
                             * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
                             * for details over the differences between `_.debounce` and `_.throttle`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Function
                             * @param {Function} func The function to debounce.
                             * @param {number} [wait=0] The number of milliseconds to delay.
                             * @param {Object} [options={}] The options object.
                             * @param {boolean} [options.leading=false]
                             *  Specify invoking on the leading edge of the timeout.
                             * @param {number} [options.maxWait]
                             *  The maximum time `func` is allowed to be delayed before it's invoked.
                             * @param {boolean} [options.trailing=true]
                             *  Specify invoking on the trailing edge of the timeout.
                             * @returns {Function} Returns the new debounced function.
                             * @example
                             *
                             * // Avoid costly calculations while the window size is in flux.
                             * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
                             *
                             * // Invoke `sendMail` when clicked, debouncing subsequent calls.
                             * jQuery(element).on('click', _.debounce(sendMail, 300, {
                             *   'leading': true,
                             *   'trailing': false
                             * }));
                             *
                             * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
                             * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
                             * var source = new EventSource('/stream');
                             * jQuery(source).on('message', debounced);
                             *
                             * // Cancel the trailing debounced invocation.
                             * jQuery(window).on('popstate', debounced.cancel);
                             */
                            function debounce(func, wait, options) {
                                var lastArgs,
                                    lastThis,
                                    maxWait,
                                    result,
                                    timerId,
                                    lastCallTime,
                                    lastInvokeTime = 0,
                                    leading = false,
                                    maxing = false,
                                    trailing = true;

                                if (typeof func != 'function') {
                                    throw new TypeError(FUNC_ERROR_TEXT);
                                }
                                wait = toNumber(wait) || 0;
                                if (isObject(options)) {
                                    leading = !!options.leading;
                                    maxing = 'maxWait' in options;
                                    maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
                                    trailing = 'trailing' in options ? !!options.trailing : trailing;
                                }

                                function invokeFunc(time) {
                                    var args = lastArgs,
                                        thisArg = lastThis;

                                    lastArgs = lastThis = undefined;
                                    lastInvokeTime = time;
                                    result = func.apply(thisArg, args);
                                    return result;
                                }

                                function leadingEdge(time) {
                                    // Reset any `maxWait` timer.
                                    lastInvokeTime = time;
                                    // Start the timer for the trailing edge.
                                    timerId = setTimeout(timerExpired, wait);
                                    // Invoke the leading edge.
                                    return leading ? invokeFunc(time) : result;
                                }

                                function remainingWait(time) {
                                    var timeSinceLastCall = time - lastCallTime,
                                        timeSinceLastInvoke = time - lastInvokeTime,
                                        timeWaiting = wait - timeSinceLastCall;

                                    return maxing
                                        ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
                                        : timeWaiting;
                                }

                                function shouldInvoke(time) {
                                    var timeSinceLastCall = time - lastCallTime,
                                        timeSinceLastInvoke = time - lastInvokeTime;

                                    // Either this is the first call, activity has stopped and we're at the
                                    // trailing edge, the system time has gone backwards and we're treating
                                    // it as the trailing edge, or we've hit the `maxWait` limit.
                                    return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
                                        (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
                                }

                                function timerExpired() {
                                    var time = now();
                                    if (shouldInvoke(time)) {
                                        return trailingEdge(time);
                                    }
                                    // Restart the timer.
                                    timerId = setTimeout(timerExpired, remainingWait(time));
                                }

                                function trailingEdge(time) {
                                    timerId = undefined;

                                    // Only invoke if we have `lastArgs` which means `func` has been
                                    // debounced at least once.
                                    if (trailing && lastArgs) {
                                        return invokeFunc(time);
                                    }
                                    lastArgs = lastThis = undefined;
                                    return result;
                                }

                                function cancel() {
                                    if (timerId !== undefined) {
                                        clearTimeout(timerId);
                                    }
                                    lastInvokeTime = 0;
                                    lastArgs = lastCallTime = lastThis = timerId = undefined;
                                }

                                function flush() {
                                    return timerId === undefined ? result : trailingEdge(now());
                                }

                                function debounced() {
                                    var time = now(),
                                        isInvoking = shouldInvoke(time);

                                    lastArgs = arguments;
                                    lastThis = this;
                                    lastCallTime = time;

                                    if (isInvoking) {
                                        if (timerId === undefined) {
                                            return leadingEdge(lastCallTime);
                                        }
                                        if (maxing) {
                                            // Handle invocations in a tight loop.
                                            clearTimeout(timerId);
                                            timerId = setTimeout(timerExpired, wait);
                                            return invokeFunc(lastCallTime);
                                        }
                                    }
                                    if (timerId === undefined) {
                                        timerId = setTimeout(timerExpired, wait);
                                    }
                                    return result;
                                }
                                debounced.cancel = cancel;
                                debounced.flush = flush;
                                return debounced;
                            }

                            /**
                             * Defers invoking the `func` until the current call stack has cleared. Any
                             * additional arguments are provided to `func` when it's invoked.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Function
                             * @param {Function} func The function to defer.
                             * @param {...*} [args] The arguments to invoke `func` with.
                             * @returns {number} Returns the timer id.
                             * @example
                             *
                             * _.defer(function(text) {
                             *   console.log(text);
                             * }, 'deferred');
                             * // => Logs 'deferred' after one millisecond.
                             */
                            var defer = baseRest(function (func, args) {
                                return baseDelay(func, 1, args);
                            });

                            /**
                             * Invokes `func` after `wait` milliseconds. Any additional arguments are
                             * provided to `func` when it's invoked.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Function
                             * @param {Function} func The function to delay.
                             * @param {number} wait The number of milliseconds to delay invocation.
                             * @param {...*} [args] The arguments to invoke `func` with.
                             * @returns {number} Returns the timer id.
                             * @example
                             *
                             * _.delay(function(text) {
                             *   console.log(text);
                             * }, 1000, 'later');
                             * // => Logs 'later' after one second.
                             */
                            var delay = baseRest(function (func, wait, args) {
                                return baseDelay(func, toNumber(wait) || 0, args);
                            });

                            /**
                             * Creates a function that invokes `func` with arguments reversed.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Function
                             * @param {Function} func The function to flip arguments for.
                             * @returns {Function} Returns the new flipped function.
                             * @example
                             *
                             * var flipped = _.flip(function() {
                             *   return _.toArray(arguments);
                             * });
                             *
                             * flipped('a', 'b', 'c', 'd');
                             * // => ['d', 'c', 'b', 'a']
                             */
                            function flip(func) {
                                return createWrap(func, WRAP_FLIP_FLAG);
                            }

                            /**
                             * Creates a function that memoizes the result of `func`. If `resolver` is
                             * provided, it determines the cache key for storing the result based on the
                             * arguments provided to the memoized function. By default, the first argument
                             * provided to the memoized function is used as the map cache key. The `func`
                             * is invoked with the `this` binding of the memoized function.
                             *
                             * **Note:** The cache is exposed as the `cache` property on the memoized
                             * function. Its creation may be customized by replacing the `_.memoize.Cache`
                             * constructor with one whose instances implement the
                             * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
                             * method interface of `clear`, `delete`, `get`, `has`, and `set`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Function
                             * @param {Function} func The function to have its output memoized.
                             * @param {Function} [resolver] The function to resolve the cache key.
                             * @returns {Function} Returns the new memoized function.
                             * @example
                             *
                             * var object = { 'a': 1, 'b': 2 };
                             * var other = { 'c': 3, 'd': 4 };
                             *
                             * var values = _.memoize(_.values);
                             * values(object);
                             * // => [1, 2]
                             *
                             * values(other);
                             * // => [3, 4]
                             *
                             * object.a = 2;
                             * values(object);
                             * // => [1, 2]
                             *
                             * // Modify the result cache.
                             * values.cache.set(object, ['a', 'b']);
                             * values(object);
                             * // => ['a', 'b']
                             *
                             * // Replace `_.memoize.Cache`.
                             * _.memoize.Cache = WeakMap;
                             */
                            function memoize(func, resolver) {
                                if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
                                    throw new TypeError(FUNC_ERROR_TEXT);
                                }
                                var memoized = function () {
                                    var args = arguments,
                                        key = resolver ? resolver.apply(this, args) : args[0],
                                        cache = memoized.cache;

                                    if (cache.has(key)) {
                                        return cache.get(key);
                                    }
                                    var result = func.apply(this, args);
                                    memoized.cache = cache.set(key, result) || cache;
                                    return result;
                                };
                                memoized.cache = new (memoize.Cache || MapCache);
                                return memoized;
                            }

                            // Expose `MapCache`.
                            memoize.Cache = MapCache;

                            /**
                             * Creates a function that negates the result of the predicate `func`. The
                             * `func` predicate is invoked with the `this` binding and arguments of the
                             * created function.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Function
                             * @param {Function} predicate The predicate to negate.
                             * @returns {Function} Returns the new negated function.
                             * @example
                             *
                             * function isEven(n) {
                             *   return n % 2 == 0;
                             * }
                             *
                             * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
                             * // => [1, 3, 5]
                             */
                            function negate(predicate) {
                                if (typeof predicate != 'function') {
                                    throw new TypeError(FUNC_ERROR_TEXT);
                                }
                                return function () {
                                    var args = arguments;
                                    switch (args.length) {
                                        case 0: return !predicate.call(this);
                                        case 1: return !predicate.call(this, args[0]);
                                        case 2: return !predicate.call(this, args[0], args[1]);
                                        case 3: return !predicate.call(this, args[0], args[1], args[2]);
                                    }
                                    return !predicate.apply(this, args);
                                };
                            }

                            /**
                             * Creates a function that is restricted to invoking `func` once. Repeat calls
                             * to the function return the value of the first invocation. The `func` is
                             * invoked with the `this` binding and arguments of the created function.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Function
                             * @param {Function} func The function to restrict.
                             * @returns {Function} Returns the new restricted function.
                             * @example
                             *
                             * var initialize = _.once(createApplication);
                             * initialize();
                             * initialize();
                             * // => `createApplication` is invoked once
                             */
                            function once(func) {
                                return before(2, func);
                            }

                            /**
                             * Creates a function that invokes `func` with its arguments transformed.
                             *
                             * @static
                             * @since 4.0.0
                             * @memberOf _
                             * @category Function
                             * @param {Function} func The function to wrap.
                             * @param {...(Function|Function[])} [transforms=[_.identity]]
                             *  The argument transforms.
                             * @returns {Function} Returns the new function.
                             * @example
                             *
                             * function doubled(n) {
                             *   return n * 2;
                             * }
                             *
                             * function square(n) {
                             *   return n * n;
                             * }
                             *
                             * var func = _.overArgs(function(x, y) {
                             *   return [x, y];
                             * }, [square, doubled]);
                             *
                             * func(9, 3);
                             * // => [81, 6]
                             *
                             * func(10, 5);
                             * // => [100, 10]
                             */
                            var overArgs = castRest(function (func, transforms) {
                                transforms = (transforms.length == 1 && isArray(transforms[0]))
                                    ? arrayMap(transforms[0], baseUnary(getIteratee()))
                                    : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee()));

                                var funcsLength = transforms.length;
                                return baseRest(function (args) {
                                    var index = -1,
                                        length = nativeMin(args.length, funcsLength);

                                    while (++index < length) {
                                        args[index] = transforms[index].call(this, args[index]);
                                    }
                                    return apply(func, this, args);
                                });
                            });

                            /**
                             * Creates a function that invokes `func` with `partials` prepended to the
                             * arguments it receives. This method is like `_.bind` except it does **not**
                             * alter the `this` binding.
                             *
                             * The `_.partial.placeholder` value, which defaults to `_` in monolithic
                             * builds, may be used as a placeholder for partially applied arguments.
                             *
                             * **Note:** This method doesn't set the "length" property of partially
                             * applied functions.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.2.0
                             * @category Function
                             * @param {Function} func The function to partially apply arguments to.
                             * @param {...*} [partials] The arguments to be partially applied.
                             * @returns {Function} Returns the new partially applied function.
                             * @example
                             *
                             * function greet(greeting, name) {
                             *   return greeting + ' ' + name;
                             * }
                             *
                             * var sayHelloTo = _.partial(greet, 'hello');
                             * sayHelloTo('fred');
                             * // => 'hello fred'
                             *
                             * // Partially applied with placeholders.
                             * var greetFred = _.partial(greet, _, 'fred');
                             * greetFred('hi');
                             * // => 'hi fred'
                             */
                            var partial = baseRest(function (func, partials) {
                                var holders = replaceHolders(partials, getHolder(partial));
                                return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders);
                            });

                            /**
                             * This method is like `_.partial` except that partially applied arguments
                             * are appended to the arguments it receives.
                             *
                             * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
                             * builds, may be used as a placeholder for partially applied arguments.
                             *
                             * **Note:** This method doesn't set the "length" property of partially
                             * applied functions.
                             *
                             * @static
                             * @memberOf _
                             * @since 1.0.0
                             * @category Function
                             * @param {Function} func The function to partially apply arguments to.
                             * @param {...*} [partials] The arguments to be partially applied.
                             * @returns {Function} Returns the new partially applied function.
                             * @example
                             *
                             * function greet(greeting, name) {
                             *   return greeting + ' ' + name;
                             * }
                             *
                             * var greetFred = _.partialRight(greet, 'fred');
                             * greetFred('hi');
                             * // => 'hi fred'
                             *
                             * // Partially applied with placeholders.
                             * var sayHelloTo = _.partialRight(greet, 'hello', _);
                             * sayHelloTo('fred');
                             * // => 'hello fred'
                             */
                            var partialRight = baseRest(function (func, partials) {
                                var holders = replaceHolders(partials, getHolder(partialRight));
                                return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders);
                            });

                            /**
                             * Creates a function that invokes `func` with arguments arranged according
                             * to the specified `indexes` where the argument value at the first index is
                             * provided as the first argument, the argument value at the second index is
                             * provided as the second argument, and so on.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Function
                             * @param {Function} func The function to rearrange arguments for.
                             * @param {...(number|number[])} indexes The arranged argument indexes.
                             * @returns {Function} Returns the new function.
                             * @example
                             *
                             * var rearged = _.rearg(function(a, b, c) {
                             *   return [a, b, c];
                             * }, [2, 0, 1]);
                             *
                             * rearged('b', 'c', 'a')
                             * // => ['a', 'b', 'c']
                             */
                            var rearg = flatRest(function (func, indexes) {
                                return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes);
                            });

                            /**
                             * Creates a function that invokes `func` with the `this` binding of the
                             * created function and arguments from `start` and beyond provided as
                             * an array.
                             *
                             * **Note:** This method is based on the
                             * [rest parameter](https://mdn.io/rest_parameters).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Function
                             * @param {Function} func The function to apply a rest parameter to.
                             * @param {number} [start=func.length-1] The start position of the rest parameter.
                             * @returns {Function} Returns the new function.
                             * @example
                             *
                             * var say = _.rest(function(what, names) {
                             *   return what + ' ' + _.initial(names).join(', ') +
                             *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);
                             * });
                             *
                             * say('hello', 'fred', 'barney', 'pebbles');
                             * // => 'hello fred, barney, & pebbles'
                             */
                            function rest(func, start) {
                                if (typeof func != 'function') {
                                    throw new TypeError(FUNC_ERROR_TEXT);
                                }
                                start = start === undefined ? start : toInteger(start);
                                return baseRest(func, start);
                            }

                            /**
                             * Creates a function that invokes `func` with the `this` binding of the
                             * create function and an array of arguments much like
                             * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply).
                             *
                             * **Note:** This method is based on the
                             * [spread operator](https://mdn.io/spread_operator).
                             *
                             * @static
                             * @memberOf _
                             * @since 3.2.0
                             * @category Function
                             * @param {Function} func The function to spread arguments over.
                             * @param {number} [start=0] The start position of the spread.
                             * @returns {Function} Returns the new function.
                             * @example
                             *
                             * var say = _.spread(function(who, what) {
                             *   return who + ' says ' + what;
                             * });
                             *
                             * say(['fred', 'hello']);
                             * // => 'fred says hello'
                             *
                             * var numbers = Promise.all([
                             *   Promise.resolve(40),
                             *   Promise.resolve(36)
                             * ]);
                             *
                             * numbers.then(_.spread(function(x, y) {
                             *   return x + y;
                             * }));
                             * // => a Promise of 76
                             */
                            function spread(func, start) {
                                if (typeof func != 'function') {
                                    throw new TypeError(FUNC_ERROR_TEXT);
                                }
                                start = start == null ? 0 : nativeMax(toInteger(start), 0);
                                return baseRest(function (args) {
                                    var array = args[start],
                                        otherArgs = castSlice(args, 0, start);

                                    if (array) {
                                        arrayPush(otherArgs, array);
                                    }
                                    return apply(func, this, otherArgs);
                                });
                            }

                            /**
                             * Creates a throttled function that only invokes `func` at most once per
                             * every `wait` milliseconds. The throttled function comes with a `cancel`
                             * method to cancel delayed `func` invocations and a `flush` method to
                             * immediately invoke them. Provide `options` to indicate whether `func`
                             * should be invoked on the leading and/or trailing edge of the `wait`
                             * timeout. The `func` is invoked with the last arguments provided to the
                             * throttled function. Subsequent calls to the throttled function return the
                             * result of the last `func` invocation.
                             *
                             * **Note:** If `leading` and `trailing` options are `true`, `func` is
                             * invoked on the trailing edge of the timeout only if the throttled function
                             * is invoked more than once during the `wait` timeout.
                             *
                             * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
                             * until to the next tick, similar to `setTimeout` with a timeout of `0`.
                             *
                             * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
                             * for details over the differences between `_.throttle` and `_.debounce`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Function
                             * @param {Function} func The function to throttle.
                             * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
                             * @param {Object} [options={}] The options object.
                             * @param {boolean} [options.leading=true]
                             *  Specify invoking on the leading edge of the timeout.
                             * @param {boolean} [options.trailing=true]
                             *  Specify invoking on the trailing edge of the timeout.
                             * @returns {Function} Returns the new throttled function.
                             * @example
                             *
                             * // Avoid excessively updating the position while scrolling.
                             * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
                             *
                             * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
                             * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
                             * jQuery(element).on('click', throttled);
                             *
                             * // Cancel the trailing throttled invocation.
                             * jQuery(window).on('popstate', throttled.cancel);
                             */
                            function throttle(func, wait, options) {
                                var leading = true,
                                    trailing = true;

                                if (typeof func != 'function') {
                                    throw new TypeError(FUNC_ERROR_TEXT);
                                }
                                if (isObject(options)) {
                                    leading = 'leading' in options ? !!options.leading : leading;
                                    trailing = 'trailing' in options ? !!options.trailing : trailing;
                                }
                                return debounce(func, wait, {
                                    'leading': leading,
                                    'maxWait': wait,
                                    'trailing': trailing
                                });
                            }

                            /**
                             * Creates a function that accepts up to one argument, ignoring any
                             * additional arguments.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Function
                             * @param {Function} func The function to cap arguments for.
                             * @returns {Function} Returns the new capped function.
                             * @example
                             *
                             * _.map(['6', '8', '10'], _.unary(parseInt));
                             * // => [6, 8, 10]
                             */
                            function unary(func) {
                                return ary(func, 1);
                            }

                            /**
                             * Creates a function that provides `value` to `wrapper` as its first
                             * argument. Any additional arguments provided to the function are appended
                             * to those provided to the `wrapper`. The wrapper is invoked with the `this`
                             * binding of the created function.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Function
                             * @param {*} value The value to wrap.
                             * @param {Function} [wrapper=identity] The wrapper function.
                             * @returns {Function} Returns the new function.
                             * @example
                             *
                             * var p = _.wrap(_.escape, function(func, text) {
                             *   return '<p>' + func(text) + '</p>';
                             * });
                             *
                             * p('fred, barney, & pebbles');
                             * // => '<p>fred, barney, &amp; pebbles</p>'
                             */
                            function wrap(value, wrapper) {
                                return partial(castFunction(wrapper), value);
                            }

                            /*------------------------------------------------------------------------*/

                            /**
                             * Casts `value` as an array if it's not one.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.4.0
                             * @category Lang
                             * @param {*} value The value to inspect.
                             * @returns {Array} Returns the cast array.
                             * @example
                             *
                             * _.castArray(1);
                             * // => [1]
                             *
                             * _.castArray({ 'a': 1 });
                             * // => [{ 'a': 1 }]
                             *
                             * _.castArray('abc');
                             * // => ['abc']
                             *
                             * _.castArray(null);
                             * // => [null]
                             *
                             * _.castArray(undefined);
                             * // => [undefined]
                             *
                             * _.castArray();
                             * // => []
                             *
                             * var array = [1, 2, 3];
                             * console.log(_.castArray(array) === array);
                             * // => true
                             */
                            function castArray() {
                                if (!arguments.length) {
                                    return [];
                                }
                                var value = arguments[0];
                                return isArray(value) ? value : [value];
                            }

                            /**
                             * Creates a shallow clone of `value`.
                             *
                             * **Note:** This method is loosely based on the
                             * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)
                             * and supports cloning arrays, array buffers, booleans, date objects, maps,
                             * numbers, `Object` objects, regexes, sets, strings, symbols, and typed
                             * arrays. The own enumerable properties of `arguments` objects are cloned
                             * as plain objects. An empty object is returned for uncloneable values such
                             * as error objects, functions, DOM nodes, and WeakMaps.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to clone.
                             * @returns {*} Returns the cloned value.
                             * @see _.cloneDeep
                             * @example
                             *
                             * var objects = [{ 'a': 1 }, { 'b': 2 }];
                             *
                             * var shallow = _.clone(objects);
                             * console.log(shallow[0] === objects[0]);
                             * // => true
                             */
                            function clone(value) {
                                return baseClone(value, CLONE_SYMBOLS_FLAG);
                            }

                            /**
                             * This method is like `_.clone` except that it accepts `customizer` which
                             * is invoked to produce the cloned value. If `customizer` returns `undefined`,
                             * cloning is handled by the method instead. The `customizer` is invoked with
                             * up to four arguments; (value [, index|key, object, stack]).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to clone.
                             * @param {Function} [customizer] The function to customize cloning.
                             * @returns {*} Returns the cloned value.
                             * @see _.cloneDeepWith
                             * @example
                             *
                             * function customizer(value) {
                             *   if (_.isElement(value)) {
                             *     return value.cloneNode(false);
                             *   }
                             * }
                             *
                             * var el = _.cloneWith(document.body, customizer);
                             *
                             * console.log(el === document.body);
                             * // => false
                             * console.log(el.nodeName);
                             * // => 'BODY'
                             * console.log(el.childNodes.length);
                             * // => 0
                             */
                            function cloneWith(value, customizer) {
                                customizer = typeof customizer == 'function' ? customizer : undefined;
                                return baseClone(value, CLONE_SYMBOLS_FLAG, customizer);
                            }

                            /**
                             * This method is like `_.clone` except that it recursively clones `value`.
                             *
                             * @static
                             * @memberOf _
                             * @since 1.0.0
                             * @category Lang
                             * @param {*} value The value to recursively clone.
                             * @returns {*} Returns the deep cloned value.
                             * @see _.clone
                             * @example
                             *
                             * var objects = [{ 'a': 1 }, { 'b': 2 }];
                             *
                             * var deep = _.cloneDeep(objects);
                             * console.log(deep[0] === objects[0]);
                             * // => false
                             */
                            function cloneDeep(value) {
                                return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
                            }

                            /**
                             * This method is like `_.cloneWith` except that it recursively clones `value`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to recursively clone.
                             * @param {Function} [customizer] The function to customize cloning.
                             * @returns {*} Returns the deep cloned value.
                             * @see _.cloneWith
                             * @example
                             *
                             * function customizer(value) {
                             *   if (_.isElement(value)) {
                             *     return value.cloneNode(true);
                             *   }
                             * }
                             *
                             * var el = _.cloneDeepWith(document.body, customizer);
                             *
                             * console.log(el === document.body);
                             * // => false
                             * console.log(el.nodeName);
                             * // => 'BODY'
                             * console.log(el.childNodes.length);
                             * // => 20
                             */
                            function cloneDeepWith(value, customizer) {
                                customizer = typeof customizer == 'function' ? customizer : undefined;
                                return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer);
                            }

                            /**
                             * Checks if `object` conforms to `source` by invoking the predicate
                             * properties of `source` with the corresponding property values of `object`.
                             *
                             * **Note:** This method is equivalent to `_.conforms` when `source` is
                             * partially applied.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.14.0
                             * @category Lang
                             * @param {Object} object The object to inspect.
                             * @param {Object} source The object of property predicates to conform to.
                             * @returns {boolean} Returns `true` if `object` conforms, else `false`.
                             * @example
                             *
                             * var object = { 'a': 1, 'b': 2 };
                             *
                             * _.conformsTo(object, { 'b': function(n) { return n > 1; } });
                             * // => true
                             *
                             * _.conformsTo(object, { 'b': function(n) { return n > 2; } });
                             * // => false
                             */
                            function conformsTo(object, source) {
                                return source == null || baseConformsTo(object, source, keys(source));
                            }

                            /**
                             * Performs a
                             * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
                             * comparison between two values to determine if they are equivalent.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to compare.
                             * @param {*} other The other value to compare.
                             * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
                             * @example
                             *
                             * var object = { 'a': 1 };
                             * var other = { 'a': 1 };
                             *
                             * _.eq(object, object);
                             * // => true
                             *
                             * _.eq(object, other);
                             * // => false
                             *
                             * _.eq('a', 'a');
                             * // => true
                             *
                             * _.eq('a', Object('a'));
                             * // => false
                             *
                             * _.eq(NaN, NaN);
                             * // => true
                             */
                            function eq(value, other) {
                                return value === other || (value !== value && other !== other);
                            }

                            /**
                             * Checks if `value` is greater than `other`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.9.0
                             * @category Lang
                             * @param {*} value The value to compare.
                             * @param {*} other The other value to compare.
                             * @returns {boolean} Returns `true` if `value` is greater than `other`,
                             *  else `false`.
                             * @see _.lt
                             * @example
                             *
                             * _.gt(3, 1);
                             * // => true
                             *
                             * _.gt(3, 3);
                             * // => false
                             *
                             * _.gt(1, 3);
                             * // => false
                             */
                            var gt = createRelationalOperation(baseGt);

                            /**
                             * Checks if `value` is greater than or equal to `other`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.9.0
                             * @category Lang
                             * @param {*} value The value to compare.
                             * @param {*} other The other value to compare.
                             * @returns {boolean} Returns `true` if `value` is greater than or equal to
                             *  `other`, else `false`.
                             * @see _.lte
                             * @example
                             *
                             * _.gte(3, 1);
                             * // => true
                             *
                             * _.gte(3, 3);
                             * // => true
                             *
                             * _.gte(1, 3);
                             * // => false
                             */
                            var gte = createRelationalOperation(function (value, other) {
                                return value >= other;
                            });

                            /**
                             * Checks if `value` is likely an `arguments` object.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is an `arguments` object,
                             *  else `false`.
                             * @example
                             *
                             * _.isArguments(function() { return arguments; }());
                             * // => true
                             *
                             * _.isArguments([1, 2, 3]);
                             * // => false
                             */
                            var isArguments = baseIsArguments(function () { return arguments; }()) ? baseIsArguments : function (value) {
                                return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&
                                    !propertyIsEnumerable.call(value, 'callee');
                            };

                            /**
                             * Checks if `value` is classified as an `Array` object.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is an array, else `false`.
                             * @example
                             *
                             * _.isArray([1, 2, 3]);
                             * // => true
                             *
                             * _.isArray(document.body.children);
                             * // => false
                             *
                             * _.isArray('abc');
                             * // => false
                             *
                             * _.isArray(_.noop);
                             * // => false
                             */
                            var isArray = Array.isArray;

                            /**
                             * Checks if `value` is classified as an `ArrayBuffer` object.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.3.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
                             * @example
                             *
                             * _.isArrayBuffer(new ArrayBuffer(2));
                             * // => true
                             *
                             * _.isArrayBuffer(new Array(2));
                             * // => false
                             */
                            var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer;

                            /**
                             * Checks if `value` is array-like. A value is considered array-like if it's
                             * not a function and has a `value.length` that's an integer greater than or
                             * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
                             * @example
                             *
                             * _.isArrayLike([1, 2, 3]);
                             * // => true
                             *
                             * _.isArrayLike(document.body.children);
                             * // => true
                             *
                             * _.isArrayLike('abc');
                             * // => true
                             *
                             * _.isArrayLike(_.noop);
                             * // => false
                             */
                            function isArrayLike(value) {
                                return value != null && isLength(value.length) && !isFunction(value);
                            }

                            /**
                             * This method is like `_.isArrayLike` except that it also checks if `value`
                             * is an object.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is an array-like object,
                             *  else `false`.
                             * @example
                             *
                             * _.isArrayLikeObject([1, 2, 3]);
                             * // => true
                             *
                             * _.isArrayLikeObject(document.body.children);
                             * // => true
                             *
                             * _.isArrayLikeObject('abc');
                             * // => false
                             *
                             * _.isArrayLikeObject(_.noop);
                             * // => false
                             */
                            function isArrayLikeObject(value) {
                                return isObjectLike(value) && isArrayLike(value);
                            }

                            /**
                             * Checks if `value` is classified as a boolean primitive or object.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a boolean, else `false`.
                             * @example
                             *
                             * _.isBoolean(false);
                             * // => true
                             *
                             * _.isBoolean(null);
                             * // => false
                             */
                            function isBoolean(value) {
                                return value === true || value === false ||
                                    (isObjectLike(value) && baseGetTag(value) == boolTag);
                            }

                            /**
                             * Checks if `value` is a buffer.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.3.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
                             * @example
                             *
                             * _.isBuffer(new Buffer(2));
                             * // => true
                             *
                             * _.isBuffer(new Uint8Array(2));
                             * // => false
                             */
                            var isBuffer = nativeIsBuffer || stubFalse;

                            /**
                             * Checks if `value` is classified as a `Date` object.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
                             * @example
                             *
                             * _.isDate(new Date);
                             * // => true
                             *
                             * _.isDate('Mon April 23 2012');
                             * // => false
                             */
                            var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;

                            /**
                             * Checks if `value` is likely a DOM element.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
                             * @example
                             *
                             * _.isElement(document.body);
                             * // => true
                             *
                             * _.isElement('<body>');
                             * // => false
                             */
                            function isElement(value) {
                                return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);
                            }

                            /**
                             * Checks if `value` is an empty object, collection, map, or set.
                             *
                             * Objects are considered empty if they have no own enumerable string keyed
                             * properties.
                             *
                             * Array-like values such as `arguments` objects, arrays, buffers, strings, or
                             * jQuery-like collections are considered empty if they have a `length` of `0`.
                             * Similarly, maps and sets are considered empty if they have a `size` of `0`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is empty, else `false`.
                             * @example
                             *
                             * _.isEmpty(null);
                             * // => true
                             *
                             * _.isEmpty(true);
                             * // => true
                             *
                             * _.isEmpty(1);
                             * // => true
                             *
                             * _.isEmpty([1, 2, 3]);
                             * // => false
                             *
                             * _.isEmpty({ 'a': 1 });
                             * // => false
                             */
                            function isEmpty(value) {
                                if (value == null) {
                                    return true;
                                }
                                if (isArrayLike(value) &&
                                    (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' ||
                                        isBuffer(value) || isTypedArray(value) || isArguments(value))) {
                                    return !value.length;
                                }
                                var tag = getTag(value);
                                if (tag == mapTag || tag == setTag) {
                                    return !value.size;
                                }
                                if (isPrototype(value)) {
                                    return !baseKeys(value).length;
                                }
                                for (var key in value) {
                                    if (hasOwnProperty.call(value, key)) {
                                        return false;
                                    }
                                }
                                return true;
                            }

                            /**
                             * Performs a deep comparison between two values to determine if they are
                             * equivalent.
                             *
                             * **Note:** This method supports comparing arrays, array buffers, booleans,
                             * date objects, error objects, maps, numbers, `Object` objects, regexes,
                             * sets, strings, symbols, and typed arrays. `Object` objects are compared
                             * by their own, not inherited, enumerable properties. Functions and DOM
                             * nodes are compared by strict equality, i.e. `===`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to compare.
                             * @param {*} other The other value to compare.
                             * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
                             * @example
                             *
                             * var object = { 'a': 1 };
                             * var other = { 'a': 1 };
                             *
                             * _.isEqual(object, other);
                             * // => true
                             *
                             * object === other;
                             * // => false
                             */
                            function isEqual(value, other) {
                                return baseIsEqual(value, other);
                            }

                            /**
                             * This method is like `_.isEqual` except that it accepts `customizer` which
                             * is invoked to compare values. If `customizer` returns `undefined`, comparisons
                             * are handled by the method instead. The `customizer` is invoked with up to
                             * six arguments: (objValue, othValue [, index|key, object, other, stack]).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to compare.
                             * @param {*} other The other value to compare.
                             * @param {Function} [customizer] The function to customize comparisons.
                             * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
                             * @example
                             *
                             * function isGreeting(value) {
                             *   return /^h(?:i|ello)$/.test(value);
                             * }
                             *
                             * function customizer(objValue, othValue) {
                             *   if (isGreeting(objValue) && isGreeting(othValue)) {
                             *     return true;
                             *   }
                             * }
                             *
                             * var array = ['hello', 'goodbye'];
                             * var other = ['hi', 'goodbye'];
                             *
                             * _.isEqualWith(array, other, customizer);
                             * // => true
                             */
                            function isEqualWith(value, other, customizer) {
                                customizer = typeof customizer == 'function' ? customizer : undefined;
                                var result = customizer ? customizer(value, other) : undefined;
                                return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result;
                            }

                            /**
                             * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
                             * `SyntaxError`, `TypeError`, or `URIError` object.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
                             * @example
                             *
                             * _.isError(new Error);
                             * // => true
                             *
                             * _.isError(Error);
                             * // => false
                             */
                            function isError(value) {
                                if (!isObjectLike(value)) {
                                    return false;
                                }
                                var tag = baseGetTag(value);
                                return tag == errorTag || tag == domExcTag ||
                                    (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value));
                            }

                            /**
                             * Checks if `value` is a finite primitive number.
                             *
                             * **Note:** This method is based on
                             * [`Number.isFinite`](https://mdn.io/Number/isFinite).
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
                             * @example
                             *
                             * _.isFinite(3);
                             * // => true
                             *
                             * _.isFinite(Number.MIN_VALUE);
                             * // => true
                             *
                             * _.isFinite(Infinity);
                             * // => false
                             *
                             * _.isFinite('3');
                             * // => false
                             */
                            function isFinite(value) {
                                return typeof value == 'number' && nativeIsFinite(value);
                            }

                            /**
                             * Checks if `value` is classified as a `Function` object.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a function, else `false`.
                             * @example
                             *
                             * _.isFunction(_);
                             * // => true
                             *
                             * _.isFunction(/abc/);
                             * // => false
                             */
                            function isFunction(value) {
                                if (!isObject(value)) {
                                    return false;
                                }
                                // The use of `Object#toString` avoids issues with the `typeof` operator
                                // in Safari 9 which returns 'object' for typed arrays and other constructors.
                                var tag = baseGetTag(value);
                                return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
                            }

                            /**
                             * Checks if `value` is an integer.
                             *
                             * **Note:** This method is based on
                             * [`Number.isInteger`](https://mdn.io/Number/isInteger).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is an integer, else `false`.
                             * @example
                             *
                             * _.isInteger(3);
                             * // => true
                             *
                             * _.isInteger(Number.MIN_VALUE);
                             * // => false
                             *
                             * _.isInteger(Infinity);
                             * // => false
                             *
                             * _.isInteger('3');
                             * // => false
                             */
                            function isInteger(value) {
                                return typeof value == 'number' && value == toInteger(value);
                            }

                            /**
                             * Checks if `value` is a valid array-like length.
                             *
                             * **Note:** This method is loosely based on
                             * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
                             * @example
                             *
                             * _.isLength(3);
                             * // => true
                             *
                             * _.isLength(Number.MIN_VALUE);
                             * // => false
                             *
                             * _.isLength(Infinity);
                             * // => false
                             *
                             * _.isLength('3');
                             * // => false
                             */
                            function isLength(value) {
                                return typeof value == 'number' &&
                                    value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
                            }

                            /**
                             * Checks if `value` is the
                             * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
                             * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is an object, else `false`.
                             * @example
                             *
                             * _.isObject({});
                             * // => true
                             *
                             * _.isObject([1, 2, 3]);
                             * // => true
                             *
                             * _.isObject(_.noop);
                             * // => true
                             *
                             * _.isObject(null);
                             * // => false
                             */
                            function isObject(value) {
                                var type = typeof value;
                                return value != null && (type == 'object' || type == 'function');
                            }

                            /**
                             * Checks if `value` is object-like. A value is object-like if it's not `null`
                             * and has a `typeof` result of "object".
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
                             * @example
                             *
                             * _.isObjectLike({});
                             * // => true
                             *
                             * _.isObjectLike([1, 2, 3]);
                             * // => true
                             *
                             * _.isObjectLike(_.noop);
                             * // => false
                             *
                             * _.isObjectLike(null);
                             * // => false
                             */
                            function isObjectLike(value) {
                                return value != null && typeof value == 'object';
                            }

                            /**
                             * Checks if `value` is classified as a `Map` object.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.3.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a map, else `false`.
                             * @example
                             *
                             * _.isMap(new Map);
                             * // => true
                             *
                             * _.isMap(new WeakMap);
                             * // => false
                             */
                            var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;

                            /**
                             * Performs a partial deep comparison between `object` and `source` to
                             * determine if `object` contains equivalent property values.
                             *
                             * **Note:** This method is equivalent to `_.matches` when `source` is
                             * partially applied.
                             *
                             * Partial comparisons will match empty array and empty object `source`
                             * values against any array or object value, respectively. See `_.isEqual`
                             * for a list of supported value comparisons.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Lang
                             * @param {Object} object The object to inspect.
                             * @param {Object} source The object of property values to match.
                             * @returns {boolean} Returns `true` if `object` is a match, else `false`.
                             * @example
                             *
                             * var object = { 'a': 1, 'b': 2 };
                             *
                             * _.isMatch(object, { 'b': 2 });
                             * // => true
                             *
                             * _.isMatch(object, { 'b': 1 });
                             * // => false
                             */
                            function isMatch(object, source) {
                                return object === source || baseIsMatch(object, source, getMatchData(source));
                            }

                            /**
                             * This method is like `_.isMatch` except that it accepts `customizer` which
                             * is invoked to compare values. If `customizer` returns `undefined`, comparisons
                             * are handled by the method instead. The `customizer` is invoked with five
                             * arguments: (objValue, srcValue, index|key, object, source).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {Object} object The object to inspect.
                             * @param {Object} source The object of property values to match.
                             * @param {Function} [customizer] The function to customize comparisons.
                             * @returns {boolean} Returns `true` if `object` is a match, else `false`.
                             * @example
                             *
                             * function isGreeting(value) {
                             *   return /^h(?:i|ello)$/.test(value);
                             * }
                             *
                             * function customizer(objValue, srcValue) {
                             *   if (isGreeting(objValue) && isGreeting(srcValue)) {
                             *     return true;
                             *   }
                             * }
                             *
                             * var object = { 'greeting': 'hello' };
                             * var source = { 'greeting': 'hi' };
                             *
                             * _.isMatchWith(object, source, customizer);
                             * // => true
                             */
                            function isMatchWith(object, source, customizer) {
                                customizer = typeof customizer == 'function' ? customizer : undefined;
                                return baseIsMatch(object, source, getMatchData(source), customizer);
                            }

                            /**
                             * Checks if `value` is `NaN`.
                             *
                             * **Note:** This method is based on
                             * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as
                             * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for
                             * `undefined` and other non-number values.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
                             * @example
                             *
                             * _.isNaN(NaN);
                             * // => true
                             *
                             * _.isNaN(new Number(NaN));
                             * // => true
                             *
                             * isNaN(undefined);
                             * // => true
                             *
                             * _.isNaN(undefined);
                             * // => false
                             */
                            function isNaN(value) {
                                // An `NaN` primitive is the only value that is not equal to itself.
                                // Perform the `toStringTag` check first to avoid errors with some
                                // ActiveX objects in IE.
                                return isNumber(value) && value != +value;
                            }

                            /**
                             * Checks if `value` is a pristine native function.
                             *
                             * **Note:** This method can't reliably detect native functions in the presence
                             * of the core-js package because core-js circumvents this kind of detection.
                             * Despite multiple requests, the core-js maintainer has made it clear: any
                             * attempt to fix the detection will be obstructed. As a result, we're left
                             * with little choice but to throw an error. Unfortunately, this also affects
                             * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill),
                             * which rely on core-js.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a native function,
                             *  else `false`.
                             * @example
                             *
                             * _.isNative(Array.prototype.push);
                             * // => true
                             *
                             * _.isNative(_);
                             * // => false
                             */
                            function isNative(value) {
                                if (isMaskable(value)) {
                                    throw new Error(CORE_ERROR_TEXT);
                                }
                                return baseIsNative(value);
                            }

                            /**
                             * Checks if `value` is `null`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
                             * @example
                             *
                             * _.isNull(null);
                             * // => true
                             *
                             * _.isNull(void 0);
                             * // => false
                             */
                            function isNull(value) {
                                return value === null;
                            }

                            /**
                             * Checks if `value` is `null` or `undefined`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is nullish, else `false`.
                             * @example
                             *
                             * _.isNil(null);
                             * // => true
                             *
                             * _.isNil(void 0);
                             * // => true
                             *
                             * _.isNil(NaN);
                             * // => false
                             */
                            function isNil(value) {
                                return value == null;
                            }

                            /**
                             * Checks if `value` is classified as a `Number` primitive or object.
                             *
                             * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are
                             * classified as numbers, use the `_.isFinite` method.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a number, else `false`.
                             * @example
                             *
                             * _.isNumber(3);
                             * // => true
                             *
                             * _.isNumber(Number.MIN_VALUE);
                             * // => true
                             *
                             * _.isNumber(Infinity);
                             * // => true
                             *
                             * _.isNumber('3');
                             * // => false
                             */
                            function isNumber(value) {
                                return typeof value == 'number' ||
                                    (isObjectLike(value) && baseGetTag(value) == numberTag);
                            }

                            /**
                             * Checks if `value` is a plain object, that is, an object created by the
                             * `Object` constructor or one with a `[[Prototype]]` of `null`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.8.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
                             * @example
                             *
                             * function Foo() {
                             *   this.a = 1;
                             * }
                             *
                             * _.isPlainObject(new Foo);
                             * // => false
                             *
                             * _.isPlainObject([1, 2, 3]);
                             * // => false
                             *
                             * _.isPlainObject({ 'x': 0, 'y': 0 });
                             * // => true
                             *
                             * _.isPlainObject(Object.create(null));
                             * // => true
                             */
                            function isPlainObject(value) {
                                if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
                                    return false;
                                }
                                var proto = getPrototype(value);
                                if (proto === null) {
                                    return true;
                                }
                                var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
                                return typeof Ctor == 'function' && Ctor instanceof Ctor &&
                                    funcToString.call(Ctor) == objectCtorString;
                            }

                            /**
                             * Checks if `value` is classified as a `RegExp` object.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.1.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
                             * @example
                             *
                             * _.isRegExp(/abc/);
                             * // => true
                             *
                             * _.isRegExp('/abc/');
                             * // => false
                             */
                            var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp;

                            /**
                             * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754
                             * double precision number which isn't the result of a rounded unsafe integer.
                             *
                             * **Note:** This method is based on
                             * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`.
                             * @example
                             *
                             * _.isSafeInteger(3);
                             * // => true
                             *
                             * _.isSafeInteger(Number.MIN_VALUE);
                             * // => false
                             *
                             * _.isSafeInteger(Infinity);
                             * // => false
                             *
                             * _.isSafeInteger('3');
                             * // => false
                             */
                            function isSafeInteger(value) {
                                return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER;
                            }

                            /**
                             * Checks if `value` is classified as a `Set` object.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.3.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a set, else `false`.
                             * @example
                             *
                             * _.isSet(new Set);
                             * // => true
                             *
                             * _.isSet(new WeakSet);
                             * // => false
                             */
                            var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;

                            /**
                             * Checks if `value` is classified as a `String` primitive or object.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a string, else `false`.
                             * @example
                             *
                             * _.isString('abc');
                             * // => true
                             *
                             * _.isString(1);
                             * // => false
                             */
                            function isString(value) {
                                return typeof value == 'string' ||
                                    (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag);
                            }

                            /**
                             * Checks if `value` is classified as a `Symbol` primitive or object.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
                             * @example
                             *
                             * _.isSymbol(Symbol.iterator);
                             * // => true
                             *
                             * _.isSymbol('abc');
                             * // => false
                             */
                            function isSymbol(value) {
                                return typeof value == 'symbol' ||
                                    (isObjectLike(value) && baseGetTag(value) == symbolTag);
                            }

                            /**
                             * Checks if `value` is classified as a typed array.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
                             * @example
                             *
                             * _.isTypedArray(new Uint8Array);
                             * // => true
                             *
                             * _.isTypedArray([]);
                             * // => false
                             */
                            var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;

                            /**
                             * Checks if `value` is `undefined`.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
                             * @example
                             *
                             * _.isUndefined(void 0);
                             * // => true
                             *
                             * _.isUndefined(null);
                             * // => false
                             */
                            function isUndefined(value) {
                                return value === undefined;
                            }

                            /**
                             * Checks if `value` is classified as a `WeakMap` object.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.3.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a weak map, else `false`.
                             * @example
                             *
                             * _.isWeakMap(new WeakMap);
                             * // => true
                             *
                             * _.isWeakMap(new Map);
                             * // => false
                             */
                            function isWeakMap(value) {
                                return isObjectLike(value) && getTag(value) == weakMapTag;
                            }

                            /**
                             * Checks if `value` is classified as a `WeakSet` object.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.3.0
                             * @category Lang
                             * @param {*} value The value to check.
                             * @returns {boolean} Returns `true` if `value` is a weak set, else `false`.
                             * @example
                             *
                             * _.isWeakSet(new WeakSet);
                             * // => true
                             *
                             * _.isWeakSet(new Set);
                             * // => false
                             */
                            function isWeakSet(value) {
                                return isObjectLike(value) && baseGetTag(value) == weakSetTag;
                            }

                            /**
                             * Checks if `value` is less than `other`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.9.0
                             * @category Lang
                             * @param {*} value The value to compare.
                             * @param {*} other The other value to compare.
                             * @returns {boolean} Returns `true` if `value` is less than `other`,
                             *  else `false`.
                             * @see _.gt
                             * @example
                             *
                             * _.lt(1, 3);
                             * // => true
                             *
                             * _.lt(3, 3);
                             * // => false
                             *
                             * _.lt(3, 1);
                             * // => false
                             */
                            var lt = createRelationalOperation(baseLt);

                            /**
                             * Checks if `value` is less than or equal to `other`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.9.0
                             * @category Lang
                             * @param {*} value The value to compare.
                             * @param {*} other The other value to compare.
                             * @returns {boolean} Returns `true` if `value` is less than or equal to
                             *  `other`, else `false`.
                             * @see _.gte
                             * @example
                             *
                             * _.lte(1, 3);
                             * // => true
                             *
                             * _.lte(3, 3);
                             * // => true
                             *
                             * _.lte(3, 1);
                             * // => false
                             */
                            var lte = createRelationalOperation(function (value, other) {
                                return value <= other;
                            });

                            /**
                             * Converts `value` to an array.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Lang
                             * @param {*} value The value to convert.
                             * @returns {Array} Returns the converted array.
                             * @example
                             *
                             * _.toArray({ 'a': 1, 'b': 2 });
                             * // => [1, 2]
                             *
                             * _.toArray('abc');
                             * // => ['a', 'b', 'c']
                             *
                             * _.toArray(1);
                             * // => []
                             *
                             * _.toArray(null);
                             * // => []
                             */
                            function toArray(value) {
                                if (!value) {
                                    return [];
                                }
                                if (isArrayLike(value)) {
                                    return isString(value) ? stringToArray(value) : copyArray(value);
                                }
                                if (symIterator && value[symIterator]) {
                                    return iteratorToArray(value[symIterator]());
                                }
                                var tag = getTag(value),
                                    func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values);

                                return func(value);
                            }

                            /**
                             * Converts `value` to a finite number.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.12.0
                             * @category Lang
                             * @param {*} value The value to convert.
                             * @returns {number} Returns the converted number.
                             * @example
                             *
                             * _.toFinite(3.2);
                             * // => 3.2
                             *
                             * _.toFinite(Number.MIN_VALUE);
                             * // => 5e-324
                             *
                             * _.toFinite(Infinity);
                             * // => 1.7976931348623157e+308
                             *
                             * _.toFinite('3.2');
                             * // => 3.2
                             */
                            function toFinite(value) {
                                if (!value) {
                                    return value === 0 ? value : 0;
                                }
                                value = toNumber(value);
                                if (value === INFINITY || value === -INFINITY) {
                                    var sign = (value < 0 ? -1 : 1);
                                    return sign * MAX_INTEGER;
                                }
                                return value === value ? value : 0;
                            }

                            /**
                             * Converts `value` to an integer.
                             *
                             * **Note:** This method is loosely based on
                             * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to convert.
                             * @returns {number} Returns the converted integer.
                             * @example
                             *
                             * _.toInteger(3.2);
                             * // => 3
                             *
                             * _.toInteger(Number.MIN_VALUE);
                             * // => 0
                             *
                             * _.toInteger(Infinity);
                             * // => 1.7976931348623157e+308
                             *
                             * _.toInteger('3.2');
                             * // => 3
                             */
                            function toInteger(value) {
                                var result = toFinite(value),
                                    remainder = result % 1;

                                return result === result ? (remainder ? result - remainder : result) : 0;
                            }

                            /**
                             * Converts `value` to an integer suitable for use as the length of an
                             * array-like object.
                             *
                             * **Note:** This method is based on
                             * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to convert.
                             * @returns {number} Returns the converted integer.
                             * @example
                             *
                             * _.toLength(3.2);
                             * // => 3
                             *
                             * _.toLength(Number.MIN_VALUE);
                             * // => 0
                             *
                             * _.toLength(Infinity);
                             * // => 4294967295
                             *
                             * _.toLength('3.2');
                             * // => 3
                             */
                            function toLength(value) {
                                return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0;
                            }

                            /**
                             * Converts `value` to a number.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to process.
                             * @returns {number} Returns the number.
                             * @example
                             *
                             * _.toNumber(3.2);
                             * // => 3.2
                             *
                             * _.toNumber(Number.MIN_VALUE);
                             * // => 5e-324
                             *
                             * _.toNumber(Infinity);
                             * // => Infinity
                             *
                             * _.toNumber('3.2');
                             * // => 3.2
                             */
                            function toNumber(value) {
                                if (typeof value == 'number') {
                                    return value;
                                }
                                if (isSymbol(value)) {
                                    return NAN;
                                }
                                if (isObject(value)) {
                                    var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
                                    value = isObject(other) ? (other + '') : other;
                                }
                                if (typeof value != 'string') {
                                    return value === 0 ? value : +value;
                                }
                                value = baseTrim(value);
                                var isBinary = reIsBinary.test(value);
                                return (isBinary || reIsOctal.test(value))
                                    ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
                                    : (reIsBadHex.test(value) ? NAN : +value);
                            }

                            /**
                             * Converts `value` to a plain object flattening inherited enumerable string
                             * keyed properties of `value` to own properties of the plain object.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Lang
                             * @param {*} value The value to convert.
                             * @returns {Object} Returns the converted plain object.
                             * @example
                             *
                             * function Foo() {
                             *   this.b = 2;
                             * }
                             *
                             * Foo.prototype.c = 3;
                             *
                             * _.assign({ 'a': 1 }, new Foo);
                             * // => { 'a': 1, 'b': 2 }
                             *
                             * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
                             * // => { 'a': 1, 'b': 2, 'c': 3 }
                             */
                            function toPlainObject(value) {
                                return copyObject(value, keysIn(value));
                            }

                            /**
                             * Converts `value` to a safe integer. A safe integer can be compared and
                             * represented correctly.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to convert.
                             * @returns {number} Returns the converted integer.
                             * @example
                             *
                             * _.toSafeInteger(3.2);
                             * // => 3
                             *
                             * _.toSafeInteger(Number.MIN_VALUE);
                             * // => 0
                             *
                             * _.toSafeInteger(Infinity);
                             * // => 9007199254740991
                             *
                             * _.toSafeInteger('3.2');
                             * // => 3
                             */
                            function toSafeInteger(value) {
                                return value
                                    ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER)
                                    : (value === 0 ? value : 0);
                            }

                            /**
                             * Converts `value` to a string. An empty string is returned for `null`
                             * and `undefined` values. The sign of `-0` is preserved.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Lang
                             * @param {*} value The value to convert.
                             * @returns {string} Returns the converted string.
                             * @example
                             *
                             * _.toString(null);
                             * // => ''
                             *
                             * _.toString(-0);
                             * // => '-0'
                             *
                             * _.toString([1, 2, 3]);
                             * // => '1,2,3'
                             */
                            function toString(value) {
                                return value == null ? '' : baseToString(value);
                            }

                            /*------------------------------------------------------------------------*/

                            /**
                             * Assigns own enumerable string keyed properties of source objects to the
                             * destination object. Source objects are applied from left to right.
                             * Subsequent sources overwrite property assignments of previous sources.
                             *
                             * **Note:** This method mutates `object` and is loosely based on
                             * [`Object.assign`](https://mdn.io/Object/assign).
                             *
                             * @static
                             * @memberOf _
                             * @since 0.10.0
                             * @category Object
                             * @param {Object} object The destination object.
                             * @param {...Object} [sources] The source objects.
                             * @returns {Object} Returns `object`.
                             * @see _.assignIn
                             * @example
                             *
                             * function Foo() {
                             *   this.a = 1;
                             * }
                             *
                             * function Bar() {
                             *   this.c = 3;
                             * }
                             *
                             * Foo.prototype.b = 2;
                             * Bar.prototype.d = 4;
                             *
                             * _.assign({ 'a': 0 }, new Foo, new Bar);
                             * // => { 'a': 1, 'c': 3 }
                             */
                            var assign = createAssigner(function (object, source) {
                                if (isPrototype(source) || isArrayLike(source)) {
                                    copyObject(source, keys(source), object);
                                    return;
                                }
                                for (var key in source) {
                                    if (hasOwnProperty.call(source, key)) {
                                        assignValue(object, key, source[key]);
                                    }
                                }
                            });

                            /**
                             * This method is like `_.assign` except that it iterates over own and
                             * inherited source properties.
                             *
                             * **Note:** This method mutates `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @alias extend
                             * @category Object
                             * @param {Object} object The destination object.
                             * @param {...Object} [sources] The source objects.
                             * @returns {Object} Returns `object`.
                             * @see _.assign
                             * @example
                             *
                             * function Foo() {
                             *   this.a = 1;
                             * }
                             *
                             * function Bar() {
                             *   this.c = 3;
                             * }
                             *
                             * Foo.prototype.b = 2;
                             * Bar.prototype.d = 4;
                             *
                             * _.assignIn({ 'a': 0 }, new Foo, new Bar);
                             * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }
                             */
                            var assignIn = createAssigner(function (object, source) {
                                copyObject(source, keysIn(source), object);
                            });

                            /**
                             * This method is like `_.assignIn` except that it accepts `customizer`
                             * which is invoked to produce the assigned values. If `customizer` returns
                             * `undefined`, assignment is handled by the method instead. The `customizer`
                             * is invoked with five arguments: (objValue, srcValue, key, object, source).
                             *
                             * **Note:** This method mutates `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @alias extendWith
                             * @category Object
                             * @param {Object} object The destination object.
                             * @param {...Object} sources The source objects.
                             * @param {Function} [customizer] The function to customize assigned values.
                             * @returns {Object} Returns `object`.
                             * @see _.assignWith
                             * @example
                             *
                             * function customizer(objValue, srcValue) {
                             *   return _.isUndefined(objValue) ? srcValue : objValue;
                             * }
                             *
                             * var defaults = _.partialRight(_.assignInWith, customizer);
                             *
                             * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
                             * // => { 'a': 1, 'b': 2 }
                             */
                            var assignInWith = createAssigner(function (object, source, srcIndex, customizer) {
                                copyObject(source, keysIn(source), object, customizer);
                            });

                            /**
                             * This method is like `_.assign` except that it accepts `customizer`
                             * which is invoked to produce the assigned values. If `customizer` returns
                             * `undefined`, assignment is handled by the method instead. The `customizer`
                             * is invoked with five arguments: (objValue, srcValue, key, object, source).
                             *
                             * **Note:** This method mutates `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Object
                             * @param {Object} object The destination object.
                             * @param {...Object} sources The source objects.
                             * @param {Function} [customizer] The function to customize assigned values.
                             * @returns {Object} Returns `object`.
                             * @see _.assignInWith
                             * @example
                             *
                             * function customizer(objValue, srcValue) {
                             *   return _.isUndefined(objValue) ? srcValue : objValue;
                             * }
                             *
                             * var defaults = _.partialRight(_.assignWith, customizer);
                             *
                             * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
                             * // => { 'a': 1, 'b': 2 }
                             */
                            var assignWith = createAssigner(function (object, source, srcIndex, customizer) {
                                copyObject(source, keys(source), object, customizer);
                            });

                            /**
                             * Creates an array of values corresponding to `paths` of `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 1.0.0
                             * @category Object
                             * @param {Object} object The object to iterate over.
                             * @param {...(string|string[])} [paths] The property paths to pick.
                             * @returns {Array} Returns the picked values.
                             * @example
                             *
                             * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
                             *
                             * _.at(object, ['a[0].b.c', 'a[1]']);
                             * // => [3, 4]
                             */
                            var at = flatRest(baseAt);

                            /**
                             * Creates an object that inherits from the `prototype` object. If a
                             * `properties` object is given, its own enumerable string keyed properties
                             * are assigned to the created object.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.3.0
                             * @category Object
                             * @param {Object} prototype The object to inherit from.
                             * @param {Object} [properties] The properties to assign to the object.
                             * @returns {Object} Returns the new object.
                             * @example
                             *
                             * function Shape() {
                             *   this.x = 0;
                             *   this.y = 0;
                             * }
                             *
                             * function Circle() {
                             *   Shape.call(this);
                             * }
                             *
                             * Circle.prototype = _.create(Shape.prototype, {
                             *   'constructor': Circle
                             * });
                             *
                             * var circle = new Circle;
                             * circle instanceof Circle;
                             * // => true
                             *
                             * circle instanceof Shape;
                             * // => true
                             */
                            function create(prototype, properties) {
                                var result = baseCreate(prototype);
                                return properties == null ? result : baseAssign(result, properties);
                            }

                            /**
                             * Assigns own and inherited enumerable string keyed properties of source
                             * objects to the destination object for all destination properties that
                             * resolve to `undefined`. Source objects are applied from left to right.
                             * Once a property is set, additional values of the same property are ignored.
                             *
                             * **Note:** This method mutates `object`.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Object
                             * @param {Object} object The destination object.
                             * @param {...Object} [sources] The source objects.
                             * @returns {Object} Returns `object`.
                             * @see _.defaultsDeep
                             * @example
                             *
                             * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
                             * // => { 'a': 1, 'b': 2 }
                             */
                            var defaults = baseRest(function (object, sources) {
                                object = Object(object);

                                var index = -1;
                                var length = sources.length;
                                var guard = length > 2 ? sources[2] : undefined;

                                if (guard && isIterateeCall(sources[0], sources[1], guard)) {
                                    length = 1;
                                }

                                while (++index < length) {
                                    var source = sources[index];
                                    var props = keysIn(source);
                                    var propsIndex = -1;
                                    var propsLength = props.length;

                                    while (++propsIndex < propsLength) {
                                        var key = props[propsIndex];
                                        var value = object[key];

                                        if (value === undefined ||
                                            (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) {
                                            object[key] = source[key];
                                        }
                                    }
                                }

                                return object;
                            });

                            /**
                             * This method is like `_.defaults` except that it recursively assigns
                             * default properties.
                             *
                             * **Note:** This method mutates `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.10.0
                             * @category Object
                             * @param {Object} object The destination object.
                             * @param {...Object} [sources] The source objects.
                             * @returns {Object} Returns `object`.
                             * @see _.defaults
                             * @example
                             *
                             * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } });
                             * // => { 'a': { 'b': 2, 'c': 3 } }
                             */
                            var defaultsDeep = baseRest(function (args) {
                                args.push(undefined, customDefaultsMerge);
                                return apply(mergeWith, undefined, args);
                            });

                            /**
                             * This method is like `_.find` except that it returns the key of the first
                             * element `predicate` returns truthy for instead of the element itself.
                             *
                             * @static
                             * @memberOf _
                             * @since 1.1.0
                             * @category Object
                             * @param {Object} object The object to inspect.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @returns {string|undefined} Returns the key of the matched element,
                             *  else `undefined`.
                             * @example
                             *
                             * var users = {
                             *   'barney':  { 'age': 36, 'active': true },
                             *   'fred':    { 'age': 40, 'active': false },
                             *   'pebbles': { 'age': 1,  'active': true }
                             * };
                             *
                             * _.findKey(users, function(o) { return o.age < 40; });
                             * // => 'barney' (iteration order is not guaranteed)
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.findKey(users, { 'age': 1, 'active': true });
                             * // => 'pebbles'
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.findKey(users, ['active', false]);
                             * // => 'fred'
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.findKey(users, 'active');
                             * // => 'barney'
                             */
                            function findKey(object, predicate) {
                                return baseFindKey(object, getIteratee(predicate, 3), baseForOwn);
                            }

                            /**
                             * This method is like `_.findKey` except that it iterates over elements of
                             * a collection in the opposite order.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.0.0
                             * @category Object
                             * @param {Object} object The object to inspect.
                             * @param {Function} [predicate=_.identity] The function invoked per iteration.
                             * @returns {string|undefined} Returns the key of the matched element,
                             *  else `undefined`.
                             * @example
                             *
                             * var users = {
                             *   'barney':  { 'age': 36, 'active': true },
                             *   'fred':    { 'age': 40, 'active': false },
                             *   'pebbles': { 'age': 1,  'active': true }
                             * };
                             *
                             * _.findLastKey(users, function(o) { return o.age < 40; });
                             * // => returns 'pebbles' assuming `_.findKey` returns 'barney'
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.findLastKey(users, { 'age': 36, 'active': true });
                             * // => 'barney'
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.findLastKey(users, ['active', false]);
                             * // => 'fred'
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.findLastKey(users, 'active');
                             * // => 'pebbles'
                             */
                            function findLastKey(object, predicate) {
                                return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight);
                            }

                            /**
                             * Iterates over own and inherited enumerable string keyed properties of an
                             * object and invokes `iteratee` for each property. The iteratee is invoked
                             * with three arguments: (value, key, object). Iteratee functions may exit
                             * iteration early by explicitly returning `false`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.3.0
                             * @category Object
                             * @param {Object} object The object to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @returns {Object} Returns `object`.
                             * @see _.forInRight
                             * @example
                             *
                             * function Foo() {
                             *   this.a = 1;
                             *   this.b = 2;
                             * }
                             *
                             * Foo.prototype.c = 3;
                             *
                             * _.forIn(new Foo, function(value, key) {
                             *   console.log(key);
                             * });
                             * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed).
                             */
                            function forIn(object, iteratee) {
                                return object == null
                                    ? object
                                    : baseFor(object, getIteratee(iteratee, 3), keysIn);
                            }

                            /**
                             * This method is like `_.forIn` except that it iterates over properties of
                             * `object` in the opposite order.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.0.0
                             * @category Object
                             * @param {Object} object The object to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @returns {Object} Returns `object`.
                             * @see _.forIn
                             * @example
                             *
                             * function Foo() {
                             *   this.a = 1;
                             *   this.b = 2;
                             * }
                             *
                             * Foo.prototype.c = 3;
                             *
                             * _.forInRight(new Foo, function(value, key) {
                             *   console.log(key);
                             * });
                             * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'.
                             */
                            function forInRight(object, iteratee) {
                                return object == null
                                    ? object
                                    : baseForRight(object, getIteratee(iteratee, 3), keysIn);
                            }

                            /**
                             * Iterates over own enumerable string keyed properties of an object and
                             * invokes `iteratee` for each property. The iteratee is invoked with three
                             * arguments: (value, key, object). Iteratee functions may exit iteration
                             * early by explicitly returning `false`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.3.0
                             * @category Object
                             * @param {Object} object The object to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @returns {Object} Returns `object`.
                             * @see _.forOwnRight
                             * @example
                             *
                             * function Foo() {
                             *   this.a = 1;
                             *   this.b = 2;
                             * }
                             *
                             * Foo.prototype.c = 3;
                             *
                             * _.forOwn(new Foo, function(value, key) {
                             *   console.log(key);
                             * });
                             * // => Logs 'a' then 'b' (iteration order is not guaranteed).
                             */
                            function forOwn(object, iteratee) {
                                return object && baseForOwn(object, getIteratee(iteratee, 3));
                            }

                            /**
                             * This method is like `_.forOwn` except that it iterates over properties of
                             * `object` in the opposite order.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.0.0
                             * @category Object
                             * @param {Object} object The object to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @returns {Object} Returns `object`.
                             * @see _.forOwn
                             * @example
                             *
                             * function Foo() {
                             *   this.a = 1;
                             *   this.b = 2;
                             * }
                             *
                             * Foo.prototype.c = 3;
                             *
                             * _.forOwnRight(new Foo, function(value, key) {
                             *   console.log(key);
                             * });
                             * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'.
                             */
                            function forOwnRight(object, iteratee) {
                                return object && baseForOwnRight(object, getIteratee(iteratee, 3));
                            }

                            /**
                             * Creates an array of function property names from own enumerable properties
                             * of `object`.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Object
                             * @param {Object} object The object to inspect.
                             * @returns {Array} Returns the function names.
                             * @see _.functionsIn
                             * @example
                             *
                             * function Foo() {
                             *   this.a = _.constant('a');
                             *   this.b = _.constant('b');
                             * }
                             *
                             * Foo.prototype.c = _.constant('c');
                             *
                             * _.functions(new Foo);
                             * // => ['a', 'b']
                             */
                            function functions(object) {
                                return object == null ? [] : baseFunctions(object, keys(object));
                            }

                            /**
                             * Creates an array of function property names from own and inherited
                             * enumerable properties of `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Object
                             * @param {Object} object The object to inspect.
                             * @returns {Array} Returns the function names.
                             * @see _.functions
                             * @example
                             *
                             * function Foo() {
                             *   this.a = _.constant('a');
                             *   this.b = _.constant('b');
                             * }
                             *
                             * Foo.prototype.c = _.constant('c');
                             *
                             * _.functionsIn(new Foo);
                             * // => ['a', 'b', 'c']
                             */
                            function functionsIn(object) {
                                return object == null ? [] : baseFunctions(object, keysIn(object));
                            }

                            /**
                             * Gets the value at `path` of `object`. If the resolved value is
                             * `undefined`, the `defaultValue` is returned in its place.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.7.0
                             * @category Object
                             * @param {Object} object The object to query.
                             * @param {Array|string} path The path of the property to get.
                             * @param {*} [defaultValue] The value returned for `undefined` resolved values.
                             * @returns {*} Returns the resolved value.
                             * @example
                             *
                             * var object = { 'a': [{ 'b': { 'c': 3 } }] };
                             *
                             * _.get(object, 'a[0].b.c');
                             * // => 3
                             *
                             * _.get(object, ['a', '0', 'b', 'c']);
                             * // => 3
                             *
                             * _.get(object, 'a.b.c', 'default');
                             * // => 'default'
                             */
                            function get(object, path, defaultValue) {
                                var result = object == null ? undefined : baseGet(object, path);
                                return result === undefined ? defaultValue : result;
                            }

                            /**
                             * Checks if `path` is a direct property of `object`.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Object
                             * @param {Object} object The object to query.
                             * @param {Array|string} path The path to check.
                             * @returns {boolean} Returns `true` if `path` exists, else `false`.
                             * @example
                             *
                             * var object = { 'a': { 'b': 2 } };
                             * var other = _.create({ 'a': _.create({ 'b': 2 }) });
                             *
                             * _.has(object, 'a');
                             * // => true
                             *
                             * _.has(object, 'a.b');
                             * // => true
                             *
                             * _.has(object, ['a', 'b']);
                             * // => true
                             *
                             * _.has(other, 'a');
                             * // => false
                             */
                            function has(object, path) {
                                return object != null && hasPath(object, path, baseHas);
                            }

                            /**
                             * Checks if `path` is a direct or inherited property of `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Object
                             * @param {Object} object The object to query.
                             * @param {Array|string} path The path to check.
                             * @returns {boolean} Returns `true` if `path` exists, else `false`.
                             * @example
                             *
                             * var object = _.create({ 'a': _.create({ 'b': 2 }) });
                             *
                             * _.hasIn(object, 'a');
                             * // => true
                             *
                             * _.hasIn(object, 'a.b');
                             * // => true
                             *
                             * _.hasIn(object, ['a', 'b']);
                             * // => true
                             *
                             * _.hasIn(object, 'b');
                             * // => false
                             */
                            function hasIn(object, path) {
                                return object != null && hasPath(object, path, baseHasIn);
                            }

                            /**
                             * Creates an object composed of the inverted keys and values of `object`.
                             * If `object` contains duplicate values, subsequent values overwrite
                             * property assignments of previous values.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.7.0
                             * @category Object
                             * @param {Object} object The object to invert.
                             * @returns {Object} Returns the new inverted object.
                             * @example
                             *
                             * var object = { 'a': 1, 'b': 2, 'c': 1 };
                             *
                             * _.invert(object);
                             * // => { '1': 'c', '2': 'b' }
                             */
                            var invert = createInverter(function (result, value, key) {
                                if (value != null &&
                                    typeof value.toString != 'function') {
                                    value = nativeObjectToString.call(value);
                                }

                                result[value] = key;
                            }, constant(identity));

                            /**
                             * This method is like `_.invert` except that the inverted object is generated
                             * from the results of running each element of `object` thru `iteratee`. The
                             * corresponding inverted value of each inverted key is an array of keys
                             * responsible for generating the inverted value. The iteratee is invoked
                             * with one argument: (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.1.0
                             * @category Object
                             * @param {Object} object The object to invert.
                             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
                             * @returns {Object} Returns the new inverted object.
                             * @example
                             *
                             * var object = { 'a': 1, 'b': 2, 'c': 1 };
                             *
                             * _.invertBy(object);
                             * // => { '1': ['a', 'c'], '2': ['b'] }
                             *
                             * _.invertBy(object, function(value) {
                             *   return 'group' + value;
                             * });
                             * // => { 'group1': ['a', 'c'], 'group2': ['b'] }
                             */
                            var invertBy = createInverter(function (result, value, key) {
                                if (value != null &&
                                    typeof value.toString != 'function') {
                                    value = nativeObjectToString.call(value);
                                }

                                if (hasOwnProperty.call(result, value)) {
                                    result[value].push(key);
                                } else {
                                    result[value] = [key];
                                }
                            }, getIteratee);

                            /**
                             * Invokes the method at `path` of `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Object
                             * @param {Object} object The object to query.
                             * @param {Array|string} path The path of the method to invoke.
                             * @param {...*} [args] The arguments to invoke the method with.
                             * @returns {*} Returns the result of the invoked method.
                             * @example
                             *
                             * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] };
                             *
                             * _.invoke(object, 'a[0].b.c.slice', 1, 3);
                             * // => [2, 3]
                             */
                            var invoke = baseRest(baseInvoke);

                            /**
                             * Creates an array of the own enumerable property names of `object`.
                             *
                             * **Note:** Non-object values are coerced to objects. See the
                             * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
                             * for more details.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Object
                             * @param {Object} object The object to query.
                             * @returns {Array} Returns the array of property names.
                             * @example
                             *
                             * function Foo() {
                             *   this.a = 1;
                             *   this.b = 2;
                             * }
                             *
                             * Foo.prototype.c = 3;
                             *
                             * _.keys(new Foo);
                             * // => ['a', 'b'] (iteration order is not guaranteed)
                             *
                             * _.keys('hi');
                             * // => ['0', '1']
                             */
                            function keys(object) {
                                return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
                            }

                            /**
                             * Creates an array of the own and inherited enumerable property names of `object`.
                             *
                             * **Note:** Non-object values are coerced to objects.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Object
                             * @param {Object} object The object to query.
                             * @returns {Array} Returns the array of property names.
                             * @example
                             *
                             * function Foo() {
                             *   this.a = 1;
                             *   this.b = 2;
                             * }
                             *
                             * Foo.prototype.c = 3;
                             *
                             * _.keysIn(new Foo);
                             * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
                             */
                            function keysIn(object) {
                                return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
                            }

                            /**
                             * The opposite of `_.mapValues`; this method creates an object with the
                             * same values as `object` and keys generated by running each own enumerable
                             * string keyed property of `object` thru `iteratee`. The iteratee is invoked
                             * with three arguments: (value, key, object).
                             *
                             * @static
                             * @memberOf _
                             * @since 3.8.0
                             * @category Object
                             * @param {Object} object The object to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @returns {Object} Returns the new mapped object.
                             * @see _.mapValues
                             * @example
                             *
                             * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {
                             *   return key + value;
                             * });
                             * // => { 'a1': 1, 'b2': 2 }
                             */
                            function mapKeys(object, iteratee) {
                                var result = {};
                                iteratee = getIteratee(iteratee, 3);

                                baseForOwn(object, function (value, key, object) {
                                    baseAssignValue(result, iteratee(value, key, object), value);
                                });
                                return result;
                            }

                            /**
                             * Creates an object with the same keys as `object` and values generated
                             * by running each own enumerable string keyed property of `object` thru
                             * `iteratee`. The iteratee is invoked with three arguments:
                             * (value, key, object).
                             *
                             * @static
                             * @memberOf _
                             * @since 2.4.0
                             * @category Object
                             * @param {Object} object The object to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @returns {Object} Returns the new mapped object.
                             * @see _.mapKeys
                             * @example
                             *
                             * var users = {
                             *   'fred':    { 'user': 'fred',    'age': 40 },
                             *   'pebbles': { 'user': 'pebbles', 'age': 1 }
                             * };
                             *
                             * _.mapValues(users, function(o) { return o.age; });
                             * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.mapValues(users, 'age');
                             * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
                             */
                            function mapValues(object, iteratee) {
                                var result = {};
                                iteratee = getIteratee(iteratee, 3);

                                baseForOwn(object, function (value, key, object) {
                                    baseAssignValue(result, key, iteratee(value, key, object));
                                });
                                return result;
                            }

                            /**
                             * This method is like `_.assign` except that it recursively merges own and
                             * inherited enumerable string keyed properties of source objects into the
                             * destination object. Source properties that resolve to `undefined` are
                             * skipped if a destination value exists. Array and plain object properties
                             * are merged recursively. Other objects and value types are overridden by
                             * assignment. Source objects are applied from left to right. Subsequent
                             * sources overwrite property assignments of previous sources.
                             *
                             * **Note:** This method mutates `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.5.0
                             * @category Object
                             * @param {Object} object The destination object.
                             * @param {...Object} [sources] The source objects.
                             * @returns {Object} Returns `object`.
                             * @example
                             *
                             * var object = {
                             *   'a': [{ 'b': 2 }, { 'd': 4 }]
                             * };
                             *
                             * var other = {
                             *   'a': [{ 'c': 3 }, { 'e': 5 }]
                             * };
                             *
                             * _.merge(object, other);
                             * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
                             */
                            var merge = createAssigner(function (object, source, srcIndex) {
                                baseMerge(object, source, srcIndex);
                            });

                            /**
                             * This method is like `_.merge` except that it accepts `customizer` which
                             * is invoked to produce the merged values of the destination and source
                             * properties. If `customizer` returns `undefined`, merging is handled by the
                             * method instead. The `customizer` is invoked with six arguments:
                             * (objValue, srcValue, key, object, source, stack).
                             *
                             * **Note:** This method mutates `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Object
                             * @param {Object} object The destination object.
                             * @param {...Object} sources The source objects.
                             * @param {Function} customizer The function to customize assigned values.
                             * @returns {Object} Returns `object`.
                             * @example
                             *
                             * function customizer(objValue, srcValue) {
                             *   if (_.isArray(objValue)) {
                             *     return objValue.concat(srcValue);
                             *   }
                             * }
                             *
                             * var object = { 'a': [1], 'b': [2] };
                             * var other = { 'a': [3], 'b': [4] };
                             *
                             * _.mergeWith(object, other, customizer);
                             * // => { 'a': [1, 3], 'b': [2, 4] }
                             */
                            var mergeWith = createAssigner(function (object, source, srcIndex, customizer) {
                                baseMerge(object, source, srcIndex, customizer);
                            });

                            /**
                             * The opposite of `_.pick`; this method creates an object composed of the
                             * own and inherited enumerable property paths of `object` that are not omitted.
                             *
                             * **Note:** This method is considerably slower than `_.pick`.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Object
                             * @param {Object} object The source object.
                             * @param {...(string|string[])} [paths] The property paths to omit.
                             * @returns {Object} Returns the new object.
                             * @example
                             *
                             * var object = { 'a': 1, 'b': '2', 'c': 3 };
                             *
                             * _.omit(object, ['a', 'c']);
                             * // => { 'b': '2' }
                             */
                            var omit = flatRest(function (object, paths) {
                                var result = {};
                                if (object == null) {
                                    return result;
                                }
                                var isDeep = false;
                                paths = arrayMap(paths, function (path) {
                                    path = castPath(path, object);
                                    isDeep || (isDeep = path.length > 1);
                                    return path;
                                });
                                copyObject(object, getAllKeysIn(object), result);
                                if (isDeep) {
                                    result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone);
                                }
                                var length = paths.length;
                                while (length--) {
                                    baseUnset(result, paths[length]);
                                }
                                return result;
                            });

                            /**
                             * The opposite of `_.pickBy`; this method creates an object composed of
                             * the own and inherited enumerable string keyed properties of `object` that
                             * `predicate` doesn't return truthy for. The predicate is invoked with two
                             * arguments: (value, key).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Object
                             * @param {Object} object The source object.
                             * @param {Function} [predicate=_.identity] The function invoked per property.
                             * @returns {Object} Returns the new object.
                             * @example
                             *
                             * var object = { 'a': 1, 'b': '2', 'c': 3 };
                             *
                             * _.omitBy(object, _.isNumber);
                             * // => { 'b': '2' }
                             */
                            function omitBy(object, predicate) {
                                return pickBy(object, negate(getIteratee(predicate)));
                            }

                            /**
                             * Creates an object composed of the picked `object` properties.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Object
                             * @param {Object} object The source object.
                             * @param {...(string|string[])} [paths] The property paths to pick.
                             * @returns {Object} Returns the new object.
                             * @example
                             *
                             * var object = { 'a': 1, 'b': '2', 'c': 3 };
                             *
                             * _.pick(object, ['a', 'c']);
                             * // => { 'a': 1, 'c': 3 }
                             */
                            var pick = flatRest(function (object, paths) {
                                return object == null ? {} : basePick(object, paths);
                            });

                            /**
                             * Creates an object composed of the `object` properties `predicate` returns
                             * truthy for. The predicate is invoked with two arguments: (value, key).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Object
                             * @param {Object} object The source object.
                             * @param {Function} [predicate=_.identity] The function invoked per property.
                             * @returns {Object} Returns the new object.
                             * @example
                             *
                             * var object = { 'a': 1, 'b': '2', 'c': 3 };
                             *
                             * _.pickBy(object, _.isNumber);
                             * // => { 'a': 1, 'c': 3 }
                             */
                            function pickBy(object, predicate) {
                                if (object == null) {
                                    return {};
                                }
                                var props = arrayMap(getAllKeysIn(object), function (prop) {
                                    return [prop];
                                });
                                predicate = getIteratee(predicate);
                                return basePickBy(object, props, function (value, path) {
                                    return predicate(value, path[0]);
                                });
                            }

                            /**
                             * This method is like `_.get` except that if the resolved value is a
                             * function it's invoked with the `this` binding of its parent object and
                             * its result is returned.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Object
                             * @param {Object} object The object to query.
                             * @param {Array|string} path The path of the property to resolve.
                             * @param {*} [defaultValue] The value returned for `undefined` resolved values.
                             * @returns {*} Returns the resolved value.
                             * @example
                             *
                             * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
                             *
                             * _.result(object, 'a[0].b.c1');
                             * // => 3
                             *
                             * _.result(object, 'a[0].b.c2');
                             * // => 4
                             *
                             * _.result(object, 'a[0].b.c3', 'default');
                             * // => 'default'
                             *
                             * _.result(object, 'a[0].b.c3', _.constant('default'));
                             * // => 'default'
                             */
                            function result(object, path, defaultValue) {
                                path = castPath(path, object);

                                var index = -1,
                                    length = path.length;

                                // Ensure the loop is entered when path is empty.
                                if (!length) {
                                    length = 1;
                                    object = undefined;
                                }
                                while (++index < length) {
                                    var value = object == null ? undefined : object[toKey(path[index])];
                                    if (value === undefined) {
                                        index = length;
                                        value = defaultValue;
                                    }
                                    object = isFunction(value) ? value.call(object) : value;
                                }
                                return object;
                            }

                            /**
                             * Sets the value at `path` of `object`. If a portion of `path` doesn't exist,
                             * it's created. Arrays are created for missing index properties while objects
                             * are created for all other missing properties. Use `_.setWith` to customize
                             * `path` creation.
                             *
                             * **Note:** This method mutates `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.7.0
                             * @category Object
                             * @param {Object} object The object to modify.
                             * @param {Array|string} path The path of the property to set.
                             * @param {*} value The value to set.
                             * @returns {Object} Returns `object`.
                             * @example
                             *
                             * var object = { 'a': [{ 'b': { 'c': 3 } }] };
                             *
                             * _.set(object, 'a[0].b.c', 4);
                             * console.log(object.a[0].b.c);
                             * // => 4
                             *
                             * _.set(object, ['x', '0', 'y', 'z'], 5);
                             * console.log(object.x[0].y.z);
                             * // => 5
                             */
                            function set(object, path, value) {
                                return object == null ? object : baseSet(object, path, value);
                            }

                            /**
                             * This method is like `_.set` except that it accepts `customizer` which is
                             * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
                             * path creation is handled by the method instead. The `customizer` is invoked
                             * with three arguments: (nsValue, key, nsObject).
                             *
                             * **Note:** This method mutates `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Object
                             * @param {Object} object The object to modify.
                             * @param {Array|string} path The path of the property to set.
                             * @param {*} value The value to set.
                             * @param {Function} [customizer] The function to customize assigned values.
                             * @returns {Object} Returns `object`.
                             * @example
                             *
                             * var object = {};
                             *
                             * _.setWith(object, '[0][1]', 'a', Object);
                             * // => { '0': { '1': 'a' } }
                             */
                            function setWith(object, path, value, customizer) {
                                customizer = typeof customizer == 'function' ? customizer : undefined;
                                return object == null ? object : baseSet(object, path, value, customizer);
                            }

                            /**
                             * Creates an array of own enumerable string keyed-value pairs for `object`
                             * which can be consumed by `_.fromPairs`. If `object` is a map or set, its
                             * entries are returned.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @alias entries
                             * @category Object
                             * @param {Object} object The object to query.
                             * @returns {Array} Returns the key-value pairs.
                             * @example
                             *
                             * function Foo() {
                             *   this.a = 1;
                             *   this.b = 2;
                             * }
                             *
                             * Foo.prototype.c = 3;
                             *
                             * _.toPairs(new Foo);
                             * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
                             */
                            var toPairs = createToPairs(keys);

                            /**
                             * Creates an array of own and inherited enumerable string keyed-value pairs
                             * for `object` which can be consumed by `_.fromPairs`. If `object` is a map
                             * or set, its entries are returned.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @alias entriesIn
                             * @category Object
                             * @param {Object} object The object to query.
                             * @returns {Array} Returns the key-value pairs.
                             * @example
                             *
                             * function Foo() {
                             *   this.a = 1;
                             *   this.b = 2;
                             * }
                             *
                             * Foo.prototype.c = 3;
                             *
                             * _.toPairsIn(new Foo);
                             * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed)
                             */
                            var toPairsIn = createToPairs(keysIn);

                            /**
                             * An alternative to `_.reduce`; this method transforms `object` to a new
                             * `accumulator` object which is the result of running each of its own
                             * enumerable string keyed properties thru `iteratee`, with each invocation
                             * potentially mutating the `accumulator` object. If `accumulator` is not
                             * provided, a new object with the same `[[Prototype]]` will be used. The
                             * iteratee is invoked with four arguments: (accumulator, value, key, object).
                             * Iteratee functions may exit iteration early by explicitly returning `false`.
                             *
                             * @static
                             * @memberOf _
                             * @since 1.3.0
                             * @category Object
                             * @param {Object} object The object to iterate over.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @param {*} [accumulator] The custom accumulator value.
                             * @returns {*} Returns the accumulated value.
                             * @example
                             *
                             * _.transform([2, 3, 4], function(result, n) {
                             *   result.push(n *= n);
                             *   return n % 2 == 0;
                             * }, []);
                             * // => [4, 9]
                             *
                             * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
                             *   (result[value] || (result[value] = [])).push(key);
                             * }, {});
                             * // => { '1': ['a', 'c'], '2': ['b'] }
                             */
                            function transform(object, iteratee, accumulator) {
                                var isArr = isArray(object),
                                    isArrLike = isArr || isBuffer(object) || isTypedArray(object);

                                iteratee = getIteratee(iteratee, 4);
                                if (accumulator == null) {
                                    var Ctor = object && object.constructor;
                                    if (isArrLike) {
                                        accumulator = isArr ? new Ctor : [];
                                    }
                                    else if (isObject(object)) {
                                        accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {};
                                    }
                                    else {
                                        accumulator = {};
                                    }
                                }
                                (isArrLike ? arrayEach : baseForOwn)(object, function (value, index, object) {
                                    return iteratee(accumulator, value, index, object);
                                });
                                return accumulator;
                            }

                            /**
                             * Removes the property at `path` of `object`.
                             *
                             * **Note:** This method mutates `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Object
                             * @param {Object} object The object to modify.
                             * @param {Array|string} path The path of the property to unset.
                             * @returns {boolean} Returns `true` if the property is deleted, else `false`.
                             * @example
                             *
                             * var object = { 'a': [{ 'b': { 'c': 7 } }] };
                             * _.unset(object, 'a[0].b.c');
                             * // => true
                             *
                             * console.log(object);
                             * // => { 'a': [{ 'b': {} }] };
                             *
                             * _.unset(object, ['a', '0', 'b', 'c']);
                             * // => true
                             *
                             * console.log(object);
                             * // => { 'a': [{ 'b': {} }] };
                             */
                            function unset(object, path) {
                                return object == null ? true : baseUnset(object, path);
                            }

                            /**
                             * This method is like `_.set` except that accepts `updater` to produce the
                             * value to set. Use `_.updateWith` to customize `path` creation. The `updater`
                             * is invoked with one argument: (value).
                             *
                             * **Note:** This method mutates `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.6.0
                             * @category Object
                             * @param {Object} object The object to modify.
                             * @param {Array|string} path The path of the property to set.
                             * @param {Function} updater The function to produce the updated value.
                             * @returns {Object} Returns `object`.
                             * @example
                             *
                             * var object = { 'a': [{ 'b': { 'c': 3 } }] };
                             *
                             * _.update(object, 'a[0].b.c', function(n) { return n * n; });
                             * console.log(object.a[0].b.c);
                             * // => 9
                             *
                             * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; });
                             * console.log(object.x[0].y.z);
                             * // => 0
                             */
                            function update(object, path, updater) {
                                return object == null ? object : baseUpdate(object, path, castFunction(updater));
                            }

                            /**
                             * This method is like `_.update` except that it accepts `customizer` which is
                             * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
                             * path creation is handled by the method instead. The `customizer` is invoked
                             * with three arguments: (nsValue, key, nsObject).
                             *
                             * **Note:** This method mutates `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.6.0
                             * @category Object
                             * @param {Object} object The object to modify.
                             * @param {Array|string} path The path of the property to set.
                             * @param {Function} updater The function to produce the updated value.
                             * @param {Function} [customizer] The function to customize assigned values.
                             * @returns {Object} Returns `object`.
                             * @example
                             *
                             * var object = {};
                             *
                             * _.updateWith(object, '[0][1]', _.constant('a'), Object);
                             * // => { '0': { '1': 'a' } }
                             */
                            function updateWith(object, path, updater, customizer) {
                                customizer = typeof customizer == 'function' ? customizer : undefined;
                                return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer);
                            }

                            /**
                             * Creates an array of the own enumerable string keyed property values of `object`.
                             *
                             * **Note:** Non-object values are coerced to objects.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Object
                             * @param {Object} object The object to query.
                             * @returns {Array} Returns the array of property values.
                             * @example
                             *
                             * function Foo() {
                             *   this.a = 1;
                             *   this.b = 2;
                             * }
                             *
                             * Foo.prototype.c = 3;
                             *
                             * _.values(new Foo);
                             * // => [1, 2] (iteration order is not guaranteed)
                             *
                             * _.values('hi');
                             * // => ['h', 'i']
                             */
                            function values(object) {
                                return object == null ? [] : baseValues(object, keys(object));
                            }

                            /**
                             * Creates an array of the own and inherited enumerable string keyed property
                             * values of `object`.
                             *
                             * **Note:** Non-object values are coerced to objects.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Object
                             * @param {Object} object The object to query.
                             * @returns {Array} Returns the array of property values.
                             * @example
                             *
                             * function Foo() {
                             *   this.a = 1;
                             *   this.b = 2;
                             * }
                             *
                             * Foo.prototype.c = 3;
                             *
                             * _.valuesIn(new Foo);
                             * // => [1, 2, 3] (iteration order is not guaranteed)
                             */
                            function valuesIn(object) {
                                return object == null ? [] : baseValues(object, keysIn(object));
                            }

                            /*------------------------------------------------------------------------*/

                            /**
                             * Clamps `number` within the inclusive `lower` and `upper` bounds.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Number
                             * @param {number} number The number to clamp.
                             * @param {number} [lower] The lower bound.
                             * @param {number} upper The upper bound.
                             * @returns {number} Returns the clamped number.
                             * @example
                             *
                             * _.clamp(-10, -5, 5);
                             * // => -5
                             *
                             * _.clamp(10, -5, 5);
                             * // => 5
                             */
                            function clamp(number, lower, upper) {
                                if (upper === undefined) {
                                    upper = lower;
                                    lower = undefined;
                                }
                                if (upper !== undefined) {
                                    upper = toNumber(upper);
                                    upper = upper === upper ? upper : 0;
                                }
                                if (lower !== undefined) {
                                    lower = toNumber(lower);
                                    lower = lower === lower ? lower : 0;
                                }
                                return baseClamp(toNumber(number), lower, upper);
                            }

                            /**
                             * Checks if `n` is between `start` and up to, but not including, `end`. If
                             * `end` is not specified, it's set to `start` with `start` then set to `0`.
                             * If `start` is greater than `end` the params are swapped to support
                             * negative ranges.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.3.0
                             * @category Number
                             * @param {number} number The number to check.
                             * @param {number} [start=0] The start of the range.
                             * @param {number} end The end of the range.
                             * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
                             * @see _.range, _.rangeRight
                             * @example
                             *
                             * _.inRange(3, 2, 4);
                             * // => true
                             *
                             * _.inRange(4, 8);
                             * // => true
                             *
                             * _.inRange(4, 2);
                             * // => false
                             *
                             * _.inRange(2, 2);
                             * // => false
                             *
                             * _.inRange(1.2, 2);
                             * // => true
                             *
                             * _.inRange(5.2, 4);
                             * // => false
                             *
                             * _.inRange(-3, -2, -6);
                             * // => true
                             */
                            function inRange(number, start, end) {
                                start = toFinite(start);
                                if (end === undefined) {
                                    end = start;
                                    start = 0;
                                } else {
                                    end = toFinite(end);
                                }
                                number = toNumber(number);
                                return baseInRange(number, start, end);
                            }

                            /**
                             * Produces a random number between the inclusive `lower` and `upper` bounds.
                             * If only one argument is provided a number between `0` and the given number
                             * is returned. If `floating` is `true`, or either `lower` or `upper` are
                             * floats, a floating-point number is returned instead of an integer.
                             *
                             * **Note:** JavaScript follows the IEEE-754 standard for resolving
                             * floating-point values which can produce unexpected results.
                             *
                             * @static
                             * @memberOf _
                             * @since 0.7.0
                             * @category Number
                             * @param {number} [lower=0] The lower bound.
                             * @param {number} [upper=1] The upper bound.
                             * @param {boolean} [floating] Specify returning a floating-point number.
                             * @returns {number} Returns the random number.
                             * @example
                             *
                             * _.random(0, 5);
                             * // => an integer between 0 and 5
                             *
                             * _.random(5);
                             * // => also an integer between 0 and 5
                             *
                             * _.random(5, true);
                             * // => a floating-point number between 0 and 5
                             *
                             * _.random(1.2, 5.2);
                             * // => a floating-point number between 1.2 and 5.2
                             */
                            function random(lower, upper, floating) {
                                if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) {
                                    upper = floating = undefined;
                                }
                                if (floating === undefined) {
                                    if (typeof upper == 'boolean') {
                                        floating = upper;
                                        upper = undefined;
                                    }
                                    else if (typeof lower == 'boolean') {
                                        floating = lower;
                                        lower = undefined;
                                    }
                                }
                                if (lower === undefined && upper === undefined) {
                                    lower = 0;
                                    upper = 1;
                                }
                                else {
                                    lower = toFinite(lower);
                                    if (upper === undefined) {
                                        upper = lower;
                                        lower = 0;
                                    } else {
                                        upper = toFinite(upper);
                                    }
                                }
                                if (lower > upper) {
                                    var temp = lower;
                                    lower = upper;
                                    upper = temp;
                                }
                                if (floating || lower % 1 || upper % 1) {
                                    var rand = nativeRandom();
                                    return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper);
                                }
                                return baseRandom(lower, upper);
                            }

                            /*------------------------------------------------------------------------*/

                            /**
                             * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category String
                             * @param {string} [string=''] The string to convert.
                             * @returns {string} Returns the camel cased string.
                             * @example
                             *
                             * _.camelCase('Foo Bar');
                             * // => 'fooBar'
                             *
                             * _.camelCase('--foo-bar--');
                             * // => 'fooBar'
                             *
                             * _.camelCase('__FOO_BAR__');
                             * // => 'fooBar'
                             */
                            var camelCase = createCompounder(function (result, word, index) {
                                word = word.toLowerCase();
                                return result + (index ? capitalize(word) : word);
                            });

                            /**
                             * Converts the first character of `string` to upper case and the remaining
                             * to lower case.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category String
                             * @param {string} [string=''] The string to capitalize.
                             * @returns {string} Returns the capitalized string.
                             * @example
                             *
                             * _.capitalize('FRED');
                             * // => 'Fred'
                             */
                            function capitalize(string) {
                                return upperFirst(toString(string).toLowerCase());
                            }

                            /**
                             * Deburrs `string` by converting
                             * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
                             * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)
                             * letters to basic Latin letters and removing
                             * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category String
                             * @param {string} [string=''] The string to deburr.
                             * @returns {string} Returns the deburred string.
                             * @example
                             *
                             * _.deburr('déjà vu');
                             * // => 'deja vu'
                             */
                            function deburr(string) {
                                string = toString(string);
                                return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
                            }

                            /**
                             * Checks if `string` ends with the given target string.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category String
                             * @param {string} [string=''] The string to inspect.
                             * @param {string} [target] The string to search for.
                             * @param {number} [position=string.length] The position to search up to.
                             * @returns {boolean} Returns `true` if `string` ends with `target`,
                             *  else `false`.
                             * @example
                             *
                             * _.endsWith('abc', 'c');
                             * // => true
                             *
                             * _.endsWith('abc', 'b');
                             * // => false
                             *
                             * _.endsWith('abc', 'b', 2);
                             * // => true
                             */
                            function endsWith(string, target, position) {
                                string = toString(string);
                                target = baseToString(target);

                                var length = string.length;
                                position = position === undefined
                                    ? length
                                    : baseClamp(toInteger(position), 0, length);

                                var end = position;
                                position -= target.length;
                                return position >= 0 && string.slice(position, end) == target;
                            }

                            /**
                             * Converts the characters "&", "<", ">", '"', and "'" in `string` to their
                             * corresponding HTML entities.
                             *
                             * **Note:** No other characters are escaped. To escape additional
                             * characters use a third-party library like [_he_](https://mths.be/he).
                             *
                             * Though the ">" character is escaped for symmetry, characters like
                             * ">" and "/" don't need escaping in HTML and have no special meaning
                             * unless they're part of a tag or unquoted attribute value. See
                             * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands)
                             * (under "semi-related fun fact") for more details.
                             *
                             * When working with HTML you should always
                             * [quote attribute values](http://wonko.com/post/html-escaping) to reduce
                             * XSS vectors.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category String
                             * @param {string} [string=''] The string to escape.
                             * @returns {string} Returns the escaped string.
                             * @example
                             *
                             * _.escape('fred, barney, & pebbles');
                             * // => 'fred, barney, &amp; pebbles'
                             */
                            function escape(string) {
                                string = toString(string);
                                return (string && reHasUnescapedHtml.test(string))
                                    ? string.replace(reUnescapedHtml, escapeHtmlChar)
                                    : string;
                            }

                            /**
                             * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
                             * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category String
                             * @param {string} [string=''] The string to escape.
                             * @returns {string} Returns the escaped string.
                             * @example
                             *
                             * _.escapeRegExp('[lodash](https://lodash.com/)');
                             * // => '\[lodash\]\(https://lodash\.com/\)'
                             */
                            function escapeRegExp(string) {
                                string = toString(string);
                                return (string && reHasRegExpChar.test(string))
                                    ? string.replace(reRegExpChar, '\\$&')
                                    : string;
                            }

                            /**
                             * Converts `string` to
                             * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category String
                             * @param {string} [string=''] The string to convert.
                             * @returns {string} Returns the kebab cased string.
                             * @example
                             *
                             * _.kebabCase('Foo Bar');
                             * // => 'foo-bar'
                             *
                             * _.kebabCase('fooBar');
                             * // => 'foo-bar'
                             *
                             * _.kebabCase('__FOO_BAR__');
                             * // => 'foo-bar'
                             */
                            var kebabCase = createCompounder(function (result, word, index) {
                                return result + (index ? '-' : '') + word.toLowerCase();
                            });

                            /**
                             * Converts `string`, as space separated words, to lower case.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category String
                             * @param {string} [string=''] The string to convert.
                             * @returns {string} Returns the lower cased string.
                             * @example
                             *
                             * _.lowerCase('--Foo-Bar--');
                             * // => 'foo bar'
                             *
                             * _.lowerCase('fooBar');
                             * // => 'foo bar'
                             *
                             * _.lowerCase('__FOO_BAR__');
                             * // => 'foo bar'
                             */
                            var lowerCase = createCompounder(function (result, word, index) {
                                return result + (index ? ' ' : '') + word.toLowerCase();
                            });

                            /**
                             * Converts the first character of `string` to lower case.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category String
                             * @param {string} [string=''] The string to convert.
                             * @returns {string} Returns the converted string.
                             * @example
                             *
                             * _.lowerFirst('Fred');
                             * // => 'fred'
                             *
                             * _.lowerFirst('FRED');
                             * // => 'fRED'
                             */
                            var lowerFirst = createCaseFirst('toLowerCase');

                            /**
                             * Pads `string` on the left and right sides if it's shorter than `length`.
                             * Padding characters are truncated if they can't be evenly divided by `length`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category String
                             * @param {string} [string=''] The string to pad.
                             * @param {number} [length=0] The padding length.
                             * @param {string} [chars=' '] The string used as padding.
                             * @returns {string} Returns the padded string.
                             * @example
                             *
                             * _.pad('abc', 8);
                             * // => '  abc   '
                             *
                             * _.pad('abc', 8, '_-');
                             * // => '_-abc_-_'
                             *
                             * _.pad('abc', 3);
                             * // => 'abc'
                             */
                            function pad(string, length, chars) {
                                string = toString(string);
                                length = toInteger(length);

                                var strLength = length ? stringSize(string) : 0;
                                if (!length || strLength >= length) {
                                    return string;
                                }
                                var mid = (length - strLength) / 2;
                                return (
                                    createPadding(nativeFloor(mid), chars) +
                                    string +
                                    createPadding(nativeCeil(mid), chars)
                                );
                            }

                            /**
                             * Pads `string` on the right side if it's shorter than `length`. Padding
                             * characters are truncated if they exceed `length`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category String
                             * @param {string} [string=''] The string to pad.
                             * @param {number} [length=0] The padding length.
                             * @param {string} [chars=' '] The string used as padding.
                             * @returns {string} Returns the padded string.
                             * @example
                             *
                             * _.padEnd('abc', 6);
                             * // => 'abc   '
                             *
                             * _.padEnd('abc', 6, '_-');
                             * // => 'abc_-_'
                             *
                             * _.padEnd('abc', 3);
                             * // => 'abc'
                             */
                            function padEnd(string, length, chars) {
                                string = toString(string);
                                length = toInteger(length);

                                var strLength = length ? stringSize(string) : 0;
                                return (length && strLength < length)
                                    ? (string + createPadding(length - strLength, chars))
                                    : string;
                            }

                            /**
                             * Pads `string` on the left side if it's shorter than `length`. Padding
                             * characters are truncated if they exceed `length`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category String
                             * @param {string} [string=''] The string to pad.
                             * @param {number} [length=0] The padding length.
                             * @param {string} [chars=' '] The string used as padding.
                             * @returns {string} Returns the padded string.
                             * @example
                             *
                             * _.padStart('abc', 6);
                             * // => '   abc'
                             *
                             * _.padStart('abc', 6, '_-');
                             * // => '_-_abc'
                             *
                             * _.padStart('abc', 3);
                             * // => 'abc'
                             */
                            function padStart(string, length, chars) {
                                string = toString(string);
                                length = toInteger(length);

                                var strLength = length ? stringSize(string) : 0;
                                return (length && strLength < length)
                                    ? (createPadding(length - strLength, chars) + string)
                                    : string;
                            }

                            /**
                             * Converts `string` to an integer of the specified radix. If `radix` is
                             * `undefined` or `0`, a `radix` of `10` is used unless `value` is a
                             * hexadecimal, in which case a `radix` of `16` is used.
                             *
                             * **Note:** This method aligns with the
                             * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`.
                             *
                             * @static
                             * @memberOf _
                             * @since 1.1.0
                             * @category String
                             * @param {string} string The string to convert.
                             * @param {number} [radix=10] The radix to interpret `value` by.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {number} Returns the converted integer.
                             * @example
                             *
                             * _.parseInt('08');
                             * // => 8
                             *
                             * _.map(['6', '08', '10'], _.parseInt);
                             * // => [6, 8, 10]
                             */
                            function parseInt(string, radix, guard) {
                                if (guard || radix == null) {
                                    radix = 0;
                                } else if (radix) {
                                    radix = +radix;
                                }
                                return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0);
                            }

                            /**
                             * Repeats the given string `n` times.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category String
                             * @param {string} [string=''] The string to repeat.
                             * @param {number} [n=1] The number of times to repeat the string.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {string} Returns the repeated string.
                             * @example
                             *
                             * _.repeat('*', 3);
                             * // => '***'
                             *
                             * _.repeat('abc', 2);
                             * // => 'abcabc'
                             *
                             * _.repeat('abc', 0);
                             * // => ''
                             */
                            function repeat(string, n, guard) {
                                if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) {
                                    n = 1;
                                } else {
                                    n = toInteger(n);
                                }
                                return baseRepeat(toString(string), n);
                            }

                            /**
                             * Replaces matches for `pattern` in `string` with `replacement`.
                             *
                             * **Note:** This method is based on
                             * [`String#replace`](https://mdn.io/String/replace).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category String
                             * @param {string} [string=''] The string to modify.
                             * @param {RegExp|string} pattern The pattern to replace.
                             * @param {Function|string} replacement The match replacement.
                             * @returns {string} Returns the modified string.
                             * @example
                             *
                             * _.replace('Hi Fred', 'Fred', 'Barney');
                             * // => 'Hi Barney'
                             */
                            function replace() {
                                var args = arguments,
                                    string = toString(args[0]);

                                return args.length < 3 ? string : string.replace(args[1], args[2]);
                            }

                            /**
                             * Converts `string` to
                             * [snake case](https://en.wikipedia.org/wiki/Snake_case).
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category String
                             * @param {string} [string=''] The string to convert.
                             * @returns {string} Returns the snake cased string.
                             * @example
                             *
                             * _.snakeCase('Foo Bar');
                             * // => 'foo_bar'
                             *
                             * _.snakeCase('fooBar');
                             * // => 'foo_bar'
                             *
                             * _.snakeCase('--FOO-BAR--');
                             * // => 'foo_bar'
                             */
                            var snakeCase = createCompounder(function (result, word, index) {
                                return result + (index ? '_' : '') + word.toLowerCase();
                            });

                            /**
                             * Splits `string` by `separator`.
                             *
                             * **Note:** This method is based on
                             * [`String#split`](https://mdn.io/String/split).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category String
                             * @param {string} [string=''] The string to split.
                             * @param {RegExp|string} separator The separator pattern to split by.
                             * @param {number} [limit] The length to truncate results to.
                             * @returns {Array} Returns the string segments.
                             * @example
                             *
                             * _.split('a-b-c', '-', 2);
                             * // => ['a', 'b']
                             */
                            function split(string, separator, limit) {
                                if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) {
                                    separator = limit = undefined;
                                }
                                limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0;
                                if (!limit) {
                                    return [];
                                }
                                string = toString(string);
                                if (string && (
                                    typeof separator == 'string' ||
                                    (separator != null && !isRegExp(separator))
                                )) {
                                    separator = baseToString(separator);
                                    if (!separator && hasUnicode(string)) {
                                        return castSlice(stringToArray(string), 0, limit);
                                    }
                                }
                                return string.split(separator, limit);
                            }

                            /**
                             * Converts `string` to
                             * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage).
                             *
                             * @static
                             * @memberOf _
                             * @since 3.1.0
                             * @category String
                             * @param {string} [string=''] The string to convert.
                             * @returns {string} Returns the start cased string.
                             * @example
                             *
                             * _.startCase('--foo-bar--');
                             * // => 'Foo Bar'
                             *
                             * _.startCase('fooBar');
                             * // => 'Foo Bar'
                             *
                             * _.startCase('__FOO_BAR__');
                             * // => 'FOO BAR'
                             */
                            var startCase = createCompounder(function (result, word, index) {
                                return result + (index ? ' ' : '') + upperFirst(word);
                            });

                            /**
                             * Checks if `string` starts with the given target string.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category String
                             * @param {string} [string=''] The string to inspect.
                             * @param {string} [target] The string to search for.
                             * @param {number} [position=0] The position to search from.
                             * @returns {boolean} Returns `true` if `string` starts with `target`,
                             *  else `false`.
                             * @example
                             *
                             * _.startsWith('abc', 'a');
                             * // => true
                             *
                             * _.startsWith('abc', 'b');
                             * // => false
                             *
                             * _.startsWith('abc', 'b', 1);
                             * // => true
                             */
                            function startsWith(string, target, position) {
                                string = toString(string);
                                position = position == null
                                    ? 0
                                    : baseClamp(toInteger(position), 0, string.length);

                                target = baseToString(target);
                                return string.slice(position, position + target.length) == target;
                            }

                            /**
                             * Creates a compiled template function that can interpolate data properties
                             * in "interpolate" delimiters, HTML-escape interpolated data properties in
                             * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
                             * properties may be accessed as free variables in the template. If a setting
                             * object is given, it takes precedence over `_.templateSettings` values.
                             *
                             * **Note:** In the development build `_.template` utilizes
                             * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
                             * for easier debugging.
                             *
                             * For more information on precompiling templates see
                             * [lodash's custom builds documentation](https://lodash.com/custom-builds).
                             *
                             * For more information on Chrome extension sandboxes see
                             * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category String
                             * @param {string} [string=''] The template string.
                             * @param {Object} [options={}] The options object.
                             * @param {RegExp} [options.escape=_.templateSettings.escape]
                             *  The HTML "escape" delimiter.
                             * @param {RegExp} [options.evaluate=_.templateSettings.evaluate]
                             *  The "evaluate" delimiter.
                             * @param {Object} [options.imports=_.templateSettings.imports]
                             *  An object to import into the template as free variables.
                             * @param {RegExp} [options.interpolate=_.templateSettings.interpolate]
                             *  The "interpolate" delimiter.
                             * @param {string} [options.sourceURL='lodash.templateSources[n]']
                             *  The sourceURL of the compiled template.
                             * @param {string} [options.variable='obj']
                             *  The data object variable name.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {Function} Returns the compiled template function.
                             * @example
                             *
                             * // Use the "interpolate" delimiter to create a compiled template.
                             * var compiled = _.template('hello <%= user %>!');
                             * compiled({ 'user': 'fred' });
                             * // => 'hello fred!'
                             *
                             * // Use the HTML "escape" delimiter to escape data property values.
                             * var compiled = _.template('<b><%- value %></b>');
                             * compiled({ 'value': '<script>' });
                             * // => '<b>&lt;script&gt;</b>'
                             *
                             * // Use the "evaluate" delimiter to execute JavaScript and generate HTML.
                             * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
                             * compiled({ 'users': ['fred', 'barney'] });
                             * // => '<li>fred</li><li>barney</li>'
                             *
                             * // Use the internal `print` function in "evaluate" delimiters.
                             * var compiled = _.template('<% print("hello " + user); %>!');
                             * compiled({ 'user': 'barney' });
                             * // => 'hello barney!'
                             *
                             * // Use the ES template literal delimiter as an "interpolate" delimiter.
                             * // Disable support by replacing the "interpolate" delimiter.
                             * var compiled = _.template('hello ${ user }!');
                             * compiled({ 'user': 'pebbles' });
                             * // => 'hello pebbles!'
                             *
                             * // Use backslashes to treat delimiters as plain text.
                             * var compiled = _.template('<%= "\\<%- value %\\>" %>');
                             * compiled({ 'value': 'ignored' });
                             * // => '<%- value %>'
                             *
                             * // Use the `imports` option to import `jQuery` as `jq`.
                             * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
                             * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
                             * compiled({ 'users': ['fred', 'barney'] });
                             * // => '<li>fred</li><li>barney</li>'
                             *
                             * // Use the `sourceURL` option to specify a custom sourceURL for the template.
                             * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
                             * compiled(data);
                             * // => Find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector.
                             *
                             * // Use the `variable` option to ensure a with-statement isn't used in the compiled template.
                             * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
                             * compiled.source;
                             * // => function(data) {
                             * //   var __t, __p = '';
                             * //   __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
                             * //   return __p;
                             * // }
                             *
                             * // Use custom template delimiters.
                             * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
                             * var compiled = _.template('hello {{ user }}!');
                             * compiled({ 'user': 'mustache' });
                             * // => 'hello mustache!'
                             *
                             * // Use the `source` property to inline compiled templates for meaningful
                             * // line numbers in error messages and stack traces.
                             * fs.writeFileSync(path.join(process.cwd(), 'jst.js'), '\
                             *   var JST = {\
                             *     "main": ' + _.template(mainText).source + '\
                             *   };\
                             * ');
                             */
                            function template(string, options, guard) {
                                // Based on John Resig's `tmpl` implementation
                                // (http://ejohn.org/blog/javascript-micro-templating/)
                                // and Laura Doktorova's doT.js (https://github.com/olado/doT).
                                var settings = lodash.templateSettings;

                                if (guard && isIterateeCall(string, options, guard)) {
                                    options = undefined;
                                }
                                string = toString(string);
                                options = assignInWith({}, options, settings, customDefaultsAssignIn);

                                var imports = assignInWith({}, options.imports, settings.imports, customDefaultsAssignIn),
                                    importsKeys = keys(imports),
                                    importsValues = baseValues(imports, importsKeys);

                                var isEscaping,
                                    isEvaluating,
                                    index = 0,
                                    interpolate = options.interpolate || reNoMatch,
                                    source = "__p += '";

                                // Compile the regexp to match each delimiter.
                                var reDelimiters = RegExp(
                                    (options.escape || reNoMatch).source + '|' +
                                    interpolate.source + '|' +
                                    (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
                                    (options.evaluate || reNoMatch).source + '|$'
                                    , 'g');

                                // Use a sourceURL for easier debugging.
                                // The sourceURL gets injected into the source that's eval-ed, so be careful
                                // to normalize all kinds of whitespace, so e.g. newlines (and unicode versions of it) can't sneak in
                                // and escape the comment, thus injecting code that gets evaled.
                                var sourceURL = '//# sourceURL=' +
                                    (hasOwnProperty.call(options, 'sourceURL')
                                        ? (options.sourceURL + '').replace(/\s/g, ' ')
                                        : ('lodash.templateSources[' + (++templateCounter) + ']')
                                    ) + '\n';

                                string.replace(reDelimiters, function (match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
                                    interpolateValue || (interpolateValue = esTemplateValue);

                                    // Escape characters that can't be included in string literals.
                                    source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);

                                    // Replace delimiters with snippets.
                                    if (escapeValue) {
                                        isEscaping = true;
                                        source += "' +\n__e(" + escapeValue + ") +\n'";
                                    }
                                    if (evaluateValue) {
                                        isEvaluating = true;
                                        source += "';\n" + evaluateValue + ";\n__p += '";
                                    }
                                    if (interpolateValue) {
                                        source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
                                    }
                                    index = offset + match.length;

                                    // The JS engine embedded in Adobe products needs `match` returned in
                                    // order to produce the correct `offset` value.
                                    return match;
                                });

                                source += "';\n";

                                // If `variable` is not specified wrap a with-statement around the generated
                                // code to add the data object to the top of the scope chain.
                                var variable = hasOwnProperty.call(options, 'variable') && options.variable;
                                if (!variable) {
                                    source = 'with (obj) {\n' + source + '\n}\n';
                                }
                                // Throw an error if a forbidden character was found in `variable`, to prevent
                                // potential command injection attacks.
                                else if (reForbiddenIdentifierChars.test(variable)) {
                                    throw new Error(INVALID_TEMPL_VAR_ERROR_TEXT);
                                }

                                // Cleanup code by stripping empty strings.
                                source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
                                    .replace(reEmptyStringMiddle, '$1')
                                    .replace(reEmptyStringTrailing, '$1;');

                                // Frame code as the function body.
                                source = 'function(' + (variable || 'obj') + ') {\n' +
                                    (variable
                                        ? ''
                                        : 'obj || (obj = {});\n'
                                    ) +
                                    "var __t, __p = ''" +
                                    (isEscaping
                                        ? ', __e = _.escape'
                                        : ''
                                    ) +
                                    (isEvaluating
                                        ? ', __j = Array.prototype.join;\n' +
                                        "function print() { __p += __j.call(arguments, '') }\n"
                                        : ';\n'
                                    ) +
                                    source +
                                    'return __p\n}';

                                var result = attempt(function () {
                                    return Function(importsKeys, sourceURL + 'return ' + source)
                                        .apply(undefined, importsValues);
                                });

                                // Provide the compiled function's source by its `toString` method or
                                // the `source` property as a convenience for inlining compiled templates.
                                result.source = source;
                                if (isError(result)) {
                                    throw result;
                                }
                                return result;
                            }

                            /**
                             * Converts `string`, as a whole, to lower case just like
                             * [String#toLowerCase](https://mdn.io/toLowerCase).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category String
                             * @param {string} [string=''] The string to convert.
                             * @returns {string} Returns the lower cased string.
                             * @example
                             *
                             * _.toLower('--Foo-Bar--');
                             * // => '--foo-bar--'
                             *
                             * _.toLower('fooBar');
                             * // => 'foobar'
                             *
                             * _.toLower('__FOO_BAR__');
                             * // => '__foo_bar__'
                             */
                            function toLower(value) {
                                return toString(value).toLowerCase();
                            }

                            /**
                             * Converts `string`, as a whole, to upper case just like
                             * [String#toUpperCase](https://mdn.io/toUpperCase).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category String
                             * @param {string} [string=''] The string to convert.
                             * @returns {string} Returns the upper cased string.
                             * @example
                             *
                             * _.toUpper('--foo-bar--');
                             * // => '--FOO-BAR--'
                             *
                             * _.toUpper('fooBar');
                             * // => 'FOOBAR'
                             *
                             * _.toUpper('__foo_bar__');
                             * // => '__FOO_BAR__'
                             */
                            function toUpper(value) {
                                return toString(value).toUpperCase();
                            }

                            /**
                             * Removes leading and trailing whitespace or specified characters from `string`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category String
                             * @param {string} [string=''] The string to trim.
                             * @param {string} [chars=whitespace] The characters to trim.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {string} Returns the trimmed string.
                             * @example
                             *
                             * _.trim('  abc  ');
                             * // => 'abc'
                             *
                             * _.trim('-_-abc-_-', '_-');
                             * // => 'abc'
                             *
                             * _.map(['  foo  ', '  bar  '], _.trim);
                             * // => ['foo', 'bar']
                             */
                            function trim(string, chars, guard) {
                                string = toString(string);
                                if (string && (guard || chars === undefined)) {
                                    return baseTrim(string);
                                }
                                if (!string || !(chars = baseToString(chars))) {
                                    return string;
                                }
                                var strSymbols = stringToArray(string),
                                    chrSymbols = stringToArray(chars),
                                    start = charsStartIndex(strSymbols, chrSymbols),
                                    end = charsEndIndex(strSymbols, chrSymbols) + 1;

                                return castSlice(strSymbols, start, end).join('');
                            }

                            /**
                             * Removes trailing whitespace or specified characters from `string`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category String
                             * @param {string} [string=''] The string to trim.
                             * @param {string} [chars=whitespace] The characters to trim.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {string} Returns the trimmed string.
                             * @example
                             *
                             * _.trimEnd('  abc  ');
                             * // => '  abc'
                             *
                             * _.trimEnd('-_-abc-_-', '_-');
                             * // => '-_-abc'
                             */
                            function trimEnd(string, chars, guard) {
                                string = toString(string);
                                if (string && (guard || chars === undefined)) {
                                    return string.slice(0, trimmedEndIndex(string) + 1);
                                }
                                if (!string || !(chars = baseToString(chars))) {
                                    return string;
                                }
                                var strSymbols = stringToArray(string),
                                    end = charsEndIndex(strSymbols, stringToArray(chars)) + 1;

                                return castSlice(strSymbols, 0, end).join('');
                            }

                            /**
                             * Removes leading whitespace or specified characters from `string`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category String
                             * @param {string} [string=''] The string to trim.
                             * @param {string} [chars=whitespace] The characters to trim.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {string} Returns the trimmed string.
                             * @example
                             *
                             * _.trimStart('  abc  ');
                             * // => 'abc  '
                             *
                             * _.trimStart('-_-abc-_-', '_-');
                             * // => 'abc-_-'
                             */
                            function trimStart(string, chars, guard) {
                                string = toString(string);
                                if (string && (guard || chars === undefined)) {
                                    return string.replace(reTrimStart, '');
                                }
                                if (!string || !(chars = baseToString(chars))) {
                                    return string;
                                }
                                var strSymbols = stringToArray(string),
                                    start = charsStartIndex(strSymbols, stringToArray(chars));

                                return castSlice(strSymbols, start).join('');
                            }

                            /**
                             * Truncates `string` if it's longer than the given maximum string length.
                             * The last characters of the truncated string are replaced with the omission
                             * string which defaults to "...".
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category String
                             * @param {string} [string=''] The string to truncate.
                             * @param {Object} [options={}] The options object.
                             * @param {number} [options.length=30] The maximum string length.
                             * @param {string} [options.omission='...'] The string to indicate text is omitted.
                             * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
                             * @returns {string} Returns the truncated string.
                             * @example
                             *
                             * _.truncate('hi-diddly-ho there, neighborino');
                             * // => 'hi-diddly-ho there, neighbo...'
                             *
                             * _.truncate('hi-diddly-ho there, neighborino', {
                             *   'length': 24,
                             *   'separator': ' '
                             * });
                             * // => 'hi-diddly-ho there,...'
                             *
                             * _.truncate('hi-diddly-ho there, neighborino', {
                             *   'length': 24,
                             *   'separator': /,? +/
                             * });
                             * // => 'hi-diddly-ho there...'
                             *
                             * _.truncate('hi-diddly-ho there, neighborino', {
                             *   'omission': ' [...]'
                             * });
                             * // => 'hi-diddly-ho there, neig [...]'
                             */
                            function truncate(string, options) {
                                var length = DEFAULT_TRUNC_LENGTH,
                                    omission = DEFAULT_TRUNC_OMISSION;

                                if (isObject(options)) {
                                    var separator = 'separator' in options ? options.separator : separator;
                                    length = 'length' in options ? toInteger(options.length) : length;
                                    omission = 'omission' in options ? baseToString(options.omission) : omission;
                                }
                                string = toString(string);

                                var strLength = string.length;
                                if (hasUnicode(string)) {
                                    var strSymbols = stringToArray(string);
                                    strLength = strSymbols.length;
                                }
                                if (length >= strLength) {
                                    return string;
                                }
                                var end = length - stringSize(omission);
                                if (end < 1) {
                                    return omission;
                                }
                                var result = strSymbols
                                    ? castSlice(strSymbols, 0, end).join('')
                                    : string.slice(0, end);

                                if (separator === undefined) {
                                    return result + omission;
                                }
                                if (strSymbols) {
                                    end += (result.length - end);
                                }
                                if (isRegExp(separator)) {
                                    if (string.slice(end).search(separator)) {
                                        var match,
                                            substring = result;

                                        if (!separator.global) {
                                            separator = RegExp(separator.source, toString(reFlags.exec(separator)) + 'g');
                                        }
                                        separator.lastIndex = 0;
                                        while ((match = separator.exec(substring))) {
                                            var newEnd = match.index;
                                        }
                                        result = result.slice(0, newEnd === undefined ? end : newEnd);
                                    }
                                } else if (string.indexOf(baseToString(separator), end) != end) {
                                    var index = result.lastIndexOf(separator);
                                    if (index > -1) {
                                        result = result.slice(0, index);
                                    }
                                }
                                return result + omission;
                            }

                            /**
                             * The inverse of `_.escape`; this method converts the HTML entities
                             * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to
                             * their corresponding characters.
                             *
                             * **Note:** No other HTML entities are unescaped. To unescape additional
                             * HTML entities use a third-party library like [_he_](https://mths.be/he).
                             *
                             * @static
                             * @memberOf _
                             * @since 0.6.0
                             * @category String
                             * @param {string} [string=''] The string to unescape.
                             * @returns {string} Returns the unescaped string.
                             * @example
                             *
                             * _.unescape('fred, barney, &amp; pebbles');
                             * // => 'fred, barney, & pebbles'
                             */
                            function unescape(string) {
                                string = toString(string);
                                return (string && reHasEscapedHtml.test(string))
                                    ? string.replace(reEscapedHtml, unescapeHtmlChar)
                                    : string;
                            }

                            /**
                             * Converts `string`, as space separated words, to upper case.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category String
                             * @param {string} [string=''] The string to convert.
                             * @returns {string} Returns the upper cased string.
                             * @example
                             *
                             * _.upperCase('--foo-bar');
                             * // => 'FOO BAR'
                             *
                             * _.upperCase('fooBar');
                             * // => 'FOO BAR'
                             *
                             * _.upperCase('__foo_bar__');
                             * // => 'FOO BAR'
                             */
                            var upperCase = createCompounder(function (result, word, index) {
                                return result + (index ? ' ' : '') + word.toUpperCase();
                            });

                            /**
                             * Converts the first character of `string` to upper case.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category String
                             * @param {string} [string=''] The string to convert.
                             * @returns {string} Returns the converted string.
                             * @example
                             *
                             * _.upperFirst('fred');
                             * // => 'Fred'
                             *
                             * _.upperFirst('FRED');
                             * // => 'FRED'
                             */
                            var upperFirst = createCaseFirst('toUpperCase');

                            /**
                             * Splits `string` into an array of its words.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category String
                             * @param {string} [string=''] The string to inspect.
                             * @param {RegExp|string} [pattern] The pattern to match words.
                             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
                             * @returns {Array} Returns the words of `string`.
                             * @example
                             *
                             * _.words('fred, barney, & pebbles');
                             * // => ['fred', 'barney', 'pebbles']
                             *
                             * _.words('fred, barney, & pebbles', /[^, ]+/g);
                             * // => ['fred', 'barney', '&', 'pebbles']
                             */
                            function words(string, pattern, guard) {
                                string = toString(string);
                                pattern = guard ? undefined : pattern;

                                if (pattern === undefined) {
                                    return hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);
                                }
                                return string.match(pattern) || [];
                            }

                            /*------------------------------------------------------------------------*/

                            /**
                             * Attempts to invoke `func`, returning either the result or the caught error
                             * object. Any additional arguments are provided to `func` when it's invoked.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Util
                             * @param {Function} func The function to attempt.
                             * @param {...*} [args] The arguments to invoke `func` with.
                             * @returns {*} Returns the `func` result or error object.
                             * @example
                             *
                             * // Avoid throwing errors for invalid selectors.
                             * var elements = _.attempt(function(selector) {
                             *   return document.querySelectorAll(selector);
                             * }, '>_>');
                             *
                             * if (_.isError(elements)) {
                             *   elements = [];
                             * }
                             */
                            var attempt = baseRest(function (func, args) {
                                try {
                                    return apply(func, undefined, args);
                                } catch (e) {
                                    return isError(e) ? e : new Error(e);
                                }
                            });

                            /**
                             * Binds methods of an object to the object itself, overwriting the existing
                             * method.
                             *
                             * **Note:** This method doesn't set the "length" property of bound functions.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Util
                             * @param {Object} object The object to bind and assign the bound methods to.
                             * @param {...(string|string[])} methodNames The object method names to bind.
                             * @returns {Object} Returns `object`.
                             * @example
                             *
                             * var view = {
                             *   'label': 'docs',
                             *   'click': function() {
                             *     console.log('clicked ' + this.label);
                             *   }
                             * };
                             *
                             * _.bindAll(view, ['click']);
                             * jQuery(element).on('click', view.click);
                             * // => Logs 'clicked docs' when clicked.
                             */
                            var bindAll = flatRest(function (object, methodNames) {
                                arrayEach(methodNames, function (key) {
                                    key = toKey(key);
                                    baseAssignValue(object, key, bind(object[key], object));
                                });
                                return object;
                            });

                            /**
                             * Creates a function that iterates over `pairs` and invokes the corresponding
                             * function of the first predicate to return truthy. The predicate-function
                             * pairs are invoked with the `this` binding and arguments of the created
                             * function.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Util
                             * @param {Array} pairs The predicate-function pairs.
                             * @returns {Function} Returns the new composite function.
                             * @example
                             *
                             * var func = _.cond([
                             *   [_.matches({ 'a': 1 }),           _.constant('matches A')],
                             *   [_.conforms({ 'b': _.isNumber }), _.constant('matches B')],
                             *   [_.stubTrue,                      _.constant('no match')]
                             * ]);
                             *
                             * func({ 'a': 1, 'b': 2 });
                             * // => 'matches A'
                             *
                             * func({ 'a': 0, 'b': 1 });
                             * // => 'matches B'
                             *
                             * func({ 'a': '1', 'b': '2' });
                             * // => 'no match'
                             */
                            function cond(pairs) {
                                var length = pairs == null ? 0 : pairs.length,
                                    toIteratee = getIteratee();

                                pairs = !length ? [] : arrayMap(pairs, function (pair) {
                                    if (typeof pair[1] != 'function') {
                                        throw new TypeError(FUNC_ERROR_TEXT);
                                    }
                                    return [toIteratee(pair[0]), pair[1]];
                                });

                                return baseRest(function (args) {
                                    var index = -1;
                                    while (++index < length) {
                                        var pair = pairs[index];
                                        if (apply(pair[0], this, args)) {
                                            return apply(pair[1], this, args);
                                        }
                                    }
                                });
                            }

                            /**
                             * Creates a function that invokes the predicate properties of `source` with
                             * the corresponding property values of a given object, returning `true` if
                             * all predicates return truthy, else `false`.
                             *
                             * **Note:** The created function is equivalent to `_.conformsTo` with
                             * `source` partially applied.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Util
                             * @param {Object} source The object of property predicates to conform to.
                             * @returns {Function} Returns the new spec function.
                             * @example
                             *
                             * var objects = [
                             *   { 'a': 2, 'b': 1 },
                             *   { 'a': 1, 'b': 2 }
                             * ];
                             *
                             * _.filter(objects, _.conforms({ 'b': function(n) { return n > 1; } }));
                             * // => [{ 'a': 1, 'b': 2 }]
                             */
                            function conforms(source) {
                                return baseConforms(baseClone(source, CLONE_DEEP_FLAG));
                            }

                            /**
                             * Creates a function that returns `value`.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.4.0
                             * @category Util
                             * @param {*} value The value to return from the new function.
                             * @returns {Function} Returns the new constant function.
                             * @example
                             *
                             * var objects = _.times(2, _.constant({ 'a': 1 }));
                             *
                             * console.log(objects);
                             * // => [{ 'a': 1 }, { 'a': 1 }]
                             *
                             * console.log(objects[0] === objects[1]);
                             * // => true
                             */
                            function constant(value) {
                                return function () {
                                    return value;
                                };
                            }

                            /**
                             * Checks `value` to determine whether a default value should be returned in
                             * its place. The `defaultValue` is returned if `value` is `NaN`, `null`,
                             * or `undefined`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.14.0
                             * @category Util
                             * @param {*} value The value to check.
                             * @param {*} defaultValue The default value.
                             * @returns {*} Returns the resolved value.
                             * @example
                             *
                             * _.defaultTo(1, 10);
                             * // => 1
                             *
                             * _.defaultTo(undefined, 10);
                             * // => 10
                             */
                            function defaultTo(value, defaultValue) {
                                return (value == null || value !== value) ? defaultValue : value;
                            }

                            /**
                             * Creates a function that returns the result of invoking the given functions
                             * with the `this` binding of the created function, where each successive
                             * invocation is supplied the return value of the previous.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Util
                             * @param {...(Function|Function[])} [funcs] The functions to invoke.
                             * @returns {Function} Returns the new composite function.
                             * @see _.flowRight
                             * @example
                             *
                             * function square(n) {
                             *   return n * n;
                             * }
                             *
                             * var addSquare = _.flow([_.add, square]);
                             * addSquare(1, 2);
                             * // => 9
                             */
                            var flow = createFlow();

                            /**
                             * This method is like `_.flow` except that it creates a function that
                             * invokes the given functions from right to left.
                             *
                             * @static
                             * @since 3.0.0
                             * @memberOf _
                             * @category Util
                             * @param {...(Function|Function[])} [funcs] The functions to invoke.
                             * @returns {Function} Returns the new composite function.
                             * @see _.flow
                             * @example
                             *
                             * function square(n) {
                             *   return n * n;
                             * }
                             *
                             * var addSquare = _.flowRight([square, _.add]);
                             * addSquare(1, 2);
                             * // => 9
                             */
                            var flowRight = createFlow(true);

                            /**
                             * This method returns the first argument it receives.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Util
                             * @param {*} value Any value.
                             * @returns {*} Returns `value`.
                             * @example
                             *
                             * var object = { 'a': 1 };
                             *
                             * console.log(_.identity(object) === object);
                             * // => true
                             */
                            function identity(value) {
                                return value;
                            }

                            /**
                             * Creates a function that invokes `func` with the arguments of the created
                             * function. If `func` is a property name, the created function returns the
                             * property value for a given element. If `func` is an array or object, the
                             * created function returns `true` for elements that contain the equivalent
                             * source properties, otherwise it returns `false`.
                             *
                             * @static
                             * @since 4.0.0
                             * @memberOf _
                             * @category Util
                             * @param {*} [func=_.identity] The value to convert to a callback.
                             * @returns {Function} Returns the callback.
                             * @example
                             *
                             * var users = [
                             *   { 'user': 'barney', 'age': 36, 'active': true },
                             *   { 'user': 'fred',   'age': 40, 'active': false }
                             * ];
                             *
                             * // The `_.matches` iteratee shorthand.
                             * _.filter(users, _.iteratee({ 'user': 'barney', 'active': true }));
                             * // => [{ 'user': 'barney', 'age': 36, 'active': true }]
                             *
                             * // The `_.matchesProperty` iteratee shorthand.
                             * _.filter(users, _.iteratee(['user', 'fred']));
                             * // => [{ 'user': 'fred', 'age': 40 }]
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.map(users, _.iteratee('user'));
                             * // => ['barney', 'fred']
                             *
                             * // Create custom iteratee shorthands.
                             * _.iteratee = _.wrap(_.iteratee, function(iteratee, func) {
                             *   return !_.isRegExp(func) ? iteratee(func) : function(string) {
                             *     return func.test(string);
                             *   };
                             * });
                             *
                             * _.filter(['abc', 'def'], /ef/);
                             * // => ['def']
                             */
                            function iteratee(func) {
                                return baseIteratee(typeof func == 'function' ? func : baseClone(func, CLONE_DEEP_FLAG));
                            }

                            /**
                             * Creates a function that performs a partial deep comparison between a given
                             * object and `source`, returning `true` if the given object has equivalent
                             * property values, else `false`.
                             *
                             * **Note:** The created function is equivalent to `_.isMatch` with `source`
                             * partially applied.
                             *
                             * Partial comparisons will match empty array and empty object `source`
                             * values against any array or object value, respectively. See `_.isEqual`
                             * for a list of supported value comparisons.
                             *
                             * **Note:** Multiple values can be checked by combining several matchers
                             * using `_.overSome`
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Util
                             * @param {Object} source The object of property values to match.
                             * @returns {Function} Returns the new spec function.
                             * @example
                             *
                             * var objects = [
                             *   { 'a': 1, 'b': 2, 'c': 3 },
                             *   { 'a': 4, 'b': 5, 'c': 6 }
                             * ];
                             *
                             * _.filter(objects, _.matches({ 'a': 4, 'c': 6 }));
                             * // => [{ 'a': 4, 'b': 5, 'c': 6 }]
                             *
                             * // Checking for several possible values
                             * _.filter(objects, _.overSome([_.matches({ 'a': 1 }), _.matches({ 'a': 4 })]));
                             * // => [{ 'a': 1, 'b': 2, 'c': 3 }, { 'a': 4, 'b': 5, 'c': 6 }]
                             */
                            function matches(source) {
                                return baseMatches(baseClone(source, CLONE_DEEP_FLAG));
                            }

                            /**
                             * Creates a function that performs a partial deep comparison between the
                             * value at `path` of a given object to `srcValue`, returning `true` if the
                             * object value is equivalent, else `false`.
                             *
                             * **Note:** Partial comparisons will match empty array and empty object
                             * `srcValue` values against any array or object value, respectively. See
                             * `_.isEqual` for a list of supported value comparisons.
                             *
                             * **Note:** Multiple values can be checked by combining several matchers
                             * using `_.overSome`
                             *
                             * @static
                             * @memberOf _
                             * @since 3.2.0
                             * @category Util
                             * @param {Array|string} path The path of the property to get.
                             * @param {*} srcValue The value to match.
                             * @returns {Function} Returns the new spec function.
                             * @example
                             *
                             * var objects = [
                             *   { 'a': 1, 'b': 2, 'c': 3 },
                             *   { 'a': 4, 'b': 5, 'c': 6 }
                             * ];
                             *
                             * _.find(objects, _.matchesProperty('a', 4));
                             * // => { 'a': 4, 'b': 5, 'c': 6 }
                             *
                             * // Checking for several possible values
                             * _.filter(objects, _.overSome([_.matchesProperty('a', 1), _.matchesProperty('a', 4)]));
                             * // => [{ 'a': 1, 'b': 2, 'c': 3 }, { 'a': 4, 'b': 5, 'c': 6 }]
                             */
                            function matchesProperty(path, srcValue) {
                                return baseMatchesProperty(path, baseClone(srcValue, CLONE_DEEP_FLAG));
                            }

                            /**
                             * Creates a function that invokes the method at `path` of a given object.
                             * Any additional arguments are provided to the invoked method.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.7.0
                             * @category Util
                             * @param {Array|string} path The path of the method to invoke.
                             * @param {...*} [args] The arguments to invoke the method with.
                             * @returns {Function} Returns the new invoker function.
                             * @example
                             *
                             * var objects = [
                             *   { 'a': { 'b': _.constant(2) } },
                             *   { 'a': { 'b': _.constant(1) } }
                             * ];
                             *
                             * _.map(objects, _.method('a.b'));
                             * // => [2, 1]
                             *
                             * _.map(objects, _.method(['a', 'b']));
                             * // => [2, 1]
                             */
                            var method = baseRest(function (path, args) {
                                return function (object) {
                                    return baseInvoke(object, path, args);
                                };
                            });

                            /**
                             * The opposite of `_.method`; this method creates a function that invokes
                             * the method at a given path of `object`. Any additional arguments are
                             * provided to the invoked method.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.7.0
                             * @category Util
                             * @param {Object} object The object to query.
                             * @param {...*} [args] The arguments to invoke the method with.
                             * @returns {Function} Returns the new invoker function.
                             * @example
                             *
                             * var array = _.times(3, _.constant),
                             *     object = { 'a': array, 'b': array, 'c': array };
                             *
                             * _.map(['a[2]', 'c[0]'], _.methodOf(object));
                             * // => [2, 0]
                             *
                             * _.map([['a', '2'], ['c', '0']], _.methodOf(object));
                             * // => [2, 0]
                             */
                            var methodOf = baseRest(function (object, args) {
                                return function (path) {
                                    return baseInvoke(object, path, args);
                                };
                            });

                            /**
                             * Adds all own enumerable string keyed function properties of a source
                             * object to the destination object. If `object` is a function, then methods
                             * are added to its prototype as well.
                             *
                             * **Note:** Use `_.runInContext` to create a pristine `lodash` function to
                             * avoid conflicts caused by modifying the original.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Util
                             * @param {Function|Object} [object=lodash] The destination object.
                             * @param {Object} source The object of functions to add.
                             * @param {Object} [options={}] The options object.
                             * @param {boolean} [options.chain=true] Specify whether mixins are chainable.
                             * @returns {Function|Object} Returns `object`.
                             * @example
                             *
                             * function vowels(string) {
                             *   return _.filter(string, function(v) {
                             *     return /[aeiou]/i.test(v);
                             *   });
                             * }
                             *
                             * _.mixin({ 'vowels': vowels });
                             * _.vowels('fred');
                             * // => ['e']
                             *
                             * _('fred').vowels().value();
                             * // => ['e']
                             *
                             * _.mixin({ 'vowels': vowels }, { 'chain': false });
                             * _('fred').vowels();
                             * // => ['e']
                             */
                            function mixin(object, source, options) {
                                var props = keys(source),
                                    methodNames = baseFunctions(source, props);

                                if (options == null &&
                                    !(isObject(source) && (methodNames.length || !props.length))) {
                                    options = source;
                                    source = object;
                                    object = this;
                                    methodNames = baseFunctions(source, keys(source));
                                }
                                var chain = !(isObject(options) && 'chain' in options) || !!options.chain,
                                    isFunc = isFunction(object);

                                arrayEach(methodNames, function (methodName) {
                                    var func = source[methodName];
                                    object[methodName] = func;
                                    if (isFunc) {
                                        object.prototype[methodName] = function () {
                                            var chainAll = this.__chain__;
                                            if (chain || chainAll) {
                                                var result = object(this.__wrapped__),
                                                    actions = result.__actions__ = copyArray(this.__actions__);

                                                actions.push({ 'func': func, 'args': arguments, 'thisArg': object });
                                                result.__chain__ = chainAll;
                                                return result;
                                            }
                                            return func.apply(object, arrayPush([this.value()], arguments));
                                        };
                                    }
                                });

                                return object;
                            }

                            /**
                             * Reverts the `_` variable to its previous value and returns a reference to
                             * the `lodash` function.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Util
                             * @returns {Function} Returns the `lodash` function.
                             * @example
                             *
                             * var lodash = _.noConflict();
                             */
                            function noConflict() {
                                if (root._ === this) {
                                    root._ = oldDash;
                                }
                                return this;
                            }

                            /**
                             * This method returns `undefined`.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.3.0
                             * @category Util
                             * @example
                             *
                             * _.times(2, _.noop);
                             * // => [undefined, undefined]
                             */
                            function noop() {
                                // No operation performed.
                            }

                            /**
                             * Creates a function that gets the argument at index `n`. If `n` is negative,
                             * the nth argument from the end is returned.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Util
                             * @param {number} [n=0] The index of the argument to return.
                             * @returns {Function} Returns the new pass-thru function.
                             * @example
                             *
                             * var func = _.nthArg(1);
                             * func('a', 'b', 'c', 'd');
                             * // => 'b'
                             *
                             * var func = _.nthArg(-2);
                             * func('a', 'b', 'c', 'd');
                             * // => 'c'
                             */
                            function nthArg(n) {
                                n = toInteger(n);
                                return baseRest(function (args) {
                                    return baseNth(args, n);
                                });
                            }

                            /**
                             * Creates a function that invokes `iteratees` with the arguments it receives
                             * and returns their results.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Util
                             * @param {...(Function|Function[])} [iteratees=[_.identity]]
                             *  The iteratees to invoke.
                             * @returns {Function} Returns the new function.
                             * @example
                             *
                             * var func = _.over([Math.max, Math.min]);
                             *
                             * func(1, 2, 3, 4);
                             * // => [4, 1]
                             */
                            var over = createOver(arrayMap);

                            /**
                             * Creates a function that checks if **all** of the `predicates` return
                             * truthy when invoked with the arguments it receives.
                             *
                             * Following shorthands are possible for providing predicates.
                             * Pass an `Object` and it will be used as an parameter for `_.matches` to create the predicate.
                             * Pass an `Array` of parameters for `_.matchesProperty` and the predicate will be created using them.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Util
                             * @param {...(Function|Function[])} [predicates=[_.identity]]
                             *  The predicates to check.
                             * @returns {Function} Returns the new function.
                             * @example
                             *
                             * var func = _.overEvery([Boolean, isFinite]);
                             *
                             * func('1');
                             * // => true
                             *
                             * func(null);
                             * // => false
                             *
                             * func(NaN);
                             * // => false
                             */
                            var overEvery = createOver(arrayEvery);

                            /**
                             * Creates a function that checks if **any** of the `predicates` return
                             * truthy when invoked with the arguments it receives.
                             *
                             * Following shorthands are possible for providing predicates.
                             * Pass an `Object` and it will be used as an parameter for `_.matches` to create the predicate.
                             * Pass an `Array` of parameters for `_.matchesProperty` and the predicate will be created using them.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Util
                             * @param {...(Function|Function[])} [predicates=[_.identity]]
                             *  The predicates to check.
                             * @returns {Function} Returns the new function.
                             * @example
                             *
                             * var func = _.overSome([Boolean, isFinite]);
                             *
                             * func('1');
                             * // => true
                             *
                             * func(null);
                             * // => true
                             *
                             * func(NaN);
                             * // => false
                             *
                             * var matchesFunc = _.overSome([{ 'a': 1 }, { 'a': 2 }])
                             * var matchesPropertyFunc = _.overSome([['a', 1], ['a', 2]])
                             */
                            var overSome = createOver(arraySome);

                            /**
                             * Creates a function that returns the value at `path` of a given object.
                             *
                             * @static
                             * @memberOf _
                             * @since 2.4.0
                             * @category Util
                             * @param {Array|string} path The path of the property to get.
                             * @returns {Function} Returns the new accessor function.
                             * @example
                             *
                             * var objects = [
                             *   { 'a': { 'b': 2 } },
                             *   { 'a': { 'b': 1 } }
                             * ];
                             *
                             * _.map(objects, _.property('a.b'));
                             * // => [2, 1]
                             *
                             * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b');
                             * // => [1, 2]
                             */
                            function property(path) {
                                return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);
                            }

                            /**
                             * The opposite of `_.property`; this method creates a function that returns
                             * the value at a given path of `object`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.0.0
                             * @category Util
                             * @param {Object} object The object to query.
                             * @returns {Function} Returns the new accessor function.
                             * @example
                             *
                             * var array = [0, 1, 2],
                             *     object = { 'a': array, 'b': array, 'c': array };
                             *
                             * _.map(['a[2]', 'c[0]'], _.propertyOf(object));
                             * // => [2, 0]
                             *
                             * _.map([['a', '2'], ['c', '0']], _.propertyOf(object));
                             * // => [2, 0]
                             */
                            function propertyOf(object) {
                                return function (path) {
                                    return object == null ? undefined : baseGet(object, path);
                                };
                            }

                            /**
                             * Creates an array of numbers (positive and/or negative) progressing from
                             * `start` up to, but not including, `end`. A step of `-1` is used if a negative
                             * `start` is specified without an `end` or `step`. If `end` is not specified,
                             * it's set to `start` with `start` then set to `0`.
                             *
                             * **Note:** JavaScript follows the IEEE-754 standard for resolving
                             * floating-point values which can produce unexpected results.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Util
                             * @param {number} [start=0] The start of the range.
                             * @param {number} end The end of the range.
                             * @param {number} [step=1] The value to increment or decrement by.
                             * @returns {Array} Returns the range of numbers.
                             * @see _.inRange, _.rangeRight
                             * @example
                             *
                             * _.range(4);
                             * // => [0, 1, 2, 3]
                             *
                             * _.range(-4);
                             * // => [0, -1, -2, -3]
                             *
                             * _.range(1, 5);
                             * // => [1, 2, 3, 4]
                             *
                             * _.range(0, 20, 5);
                             * // => [0, 5, 10, 15]
                             *
                             * _.range(0, -4, -1);
                             * // => [0, -1, -2, -3]
                             *
                             * _.range(1, 4, 0);
                             * // => [1, 1, 1]
                             *
                             * _.range(0);
                             * // => []
                             */
                            var range = createRange();

                            /**
                             * This method is like `_.range` except that it populates values in
                             * descending order.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Util
                             * @param {number} [start=0] The start of the range.
                             * @param {number} end The end of the range.
                             * @param {number} [step=1] The value to increment or decrement by.
                             * @returns {Array} Returns the range of numbers.
                             * @see _.inRange, _.range
                             * @example
                             *
                             * _.rangeRight(4);
                             * // => [3, 2, 1, 0]
                             *
                             * _.rangeRight(-4);
                             * // => [-3, -2, -1, 0]
                             *
                             * _.rangeRight(1, 5);
                             * // => [4, 3, 2, 1]
                             *
                             * _.rangeRight(0, 20, 5);
                             * // => [15, 10, 5, 0]
                             *
                             * _.rangeRight(0, -4, -1);
                             * // => [-3, -2, -1, 0]
                             *
                             * _.rangeRight(1, 4, 0);
                             * // => [1, 1, 1]
                             *
                             * _.rangeRight(0);
                             * // => []
                             */
                            var rangeRight = createRange(true);

                            /**
                             * This method returns a new empty array.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.13.0
                             * @category Util
                             * @returns {Array} Returns the new empty array.
                             * @example
                             *
                             * var arrays = _.times(2, _.stubArray);
                             *
                             * console.log(arrays);
                             * // => [[], []]
                             *
                             * console.log(arrays[0] === arrays[1]);
                             * // => false
                             */
                            function stubArray() {
                                return [];
                            }

                            /**
                             * This method returns `false`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.13.0
                             * @category Util
                             * @returns {boolean} Returns `false`.
                             * @example
                             *
                             * _.times(2, _.stubFalse);
                             * // => [false, false]
                             */
                            function stubFalse() {
                                return false;
                            }

                            /**
                             * This method returns a new empty object.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.13.0
                             * @category Util
                             * @returns {Object} Returns the new empty object.
                             * @example
                             *
                             * var objects = _.times(2, _.stubObject);
                             *
                             * console.log(objects);
                             * // => [{}, {}]
                             *
                             * console.log(objects[0] === objects[1]);
                             * // => false
                             */
                            function stubObject() {
                                return {};
                            }

                            /**
                             * This method returns an empty string.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.13.0
                             * @category Util
                             * @returns {string} Returns the empty string.
                             * @example
                             *
                             * _.times(2, _.stubString);
                             * // => ['', '']
                             */
                            function stubString() {
                                return '';
                            }

                            /**
                             * This method returns `true`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.13.0
                             * @category Util
                             * @returns {boolean} Returns `true`.
                             * @example
                             *
                             * _.times(2, _.stubTrue);
                             * // => [true, true]
                             */
                            function stubTrue() {
                                return true;
                            }

                            /**
                             * Invokes the iteratee `n` times, returning an array of the results of
                             * each invocation. The iteratee is invoked with one argument; (index).
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Util
                             * @param {number} n The number of times to invoke `iteratee`.
                             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
                             * @returns {Array} Returns the array of results.
                             * @example
                             *
                             * _.times(3, String);
                             * // => ['0', '1', '2']
                             *
                             *  _.times(4, _.constant(0));
                             * // => [0, 0, 0, 0]
                             */
                            function times(n, iteratee) {
                                n = toInteger(n);
                                if (n < 1 || n > MAX_SAFE_INTEGER) {
                                    return [];
                                }
                                var index = MAX_ARRAY_LENGTH,
                                    length = nativeMin(n, MAX_ARRAY_LENGTH);

                                iteratee = getIteratee(iteratee);
                                n -= MAX_ARRAY_LENGTH;

                                var result = baseTimes(length, iteratee);
                                while (++index < n) {
                                    iteratee(index);
                                }
                                return result;
                            }

                            /**
                             * Converts `value` to a property path array.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Util
                             * @param {*} value The value to convert.
                             * @returns {Array} Returns the new property path array.
                             * @example
                             *
                             * _.toPath('a.b.c');
                             * // => ['a', 'b', 'c']
                             *
                             * _.toPath('a[0].b.c');
                             * // => ['a', '0', 'b', 'c']
                             */
                            function toPath(value) {
                                if (isArray(value)) {
                                    return arrayMap(value, toKey);
                                }
                                return isSymbol(value) ? [value] : copyArray(stringToPath(toString(value)));
                            }

                            /**
                             * Generates a unique ID. If `prefix` is given, the ID is appended to it.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Util
                             * @param {string} [prefix=''] The value to prefix the ID with.
                             * @returns {string} Returns the unique ID.
                             * @example
                             *
                             * _.uniqueId('contact_');
                             * // => 'contact_104'
                             *
                             * _.uniqueId();
                             * // => '105'
                             */
                            function uniqueId(prefix) {
                                var id = ++idCounter;
                                return toString(prefix) + id;
                            }

                            /*------------------------------------------------------------------------*/

                            /**
                             * Adds two numbers.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.4.0
                             * @category Math
                             * @param {number} augend The first number in an addition.
                             * @param {number} addend The second number in an addition.
                             * @returns {number} Returns the total.
                             * @example
                             *
                             * _.add(6, 4);
                             * // => 10
                             */
                            var add = createMathOperation(function (augend, addend) {
                                return augend + addend;
                            }, 0);

                            /**
                             * Computes `number` rounded up to `precision`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.10.0
                             * @category Math
                             * @param {number} number The number to round up.
                             * @param {number} [precision=0] The precision to round up to.
                             * @returns {number} Returns the rounded up number.
                             * @example
                             *
                             * _.ceil(4.006);
                             * // => 5
                             *
                             * _.ceil(6.004, 2);
                             * // => 6.01
                             *
                             * _.ceil(6040, -2);
                             * // => 6100
                             */
                            var ceil = createRound('ceil');

                            /**
                             * Divide two numbers.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.7.0
                             * @category Math
                             * @param {number} dividend The first number in a division.
                             * @param {number} divisor The second number in a division.
                             * @returns {number} Returns the quotient.
                             * @example
                             *
                             * _.divide(6, 4);
                             * // => 1.5
                             */
                            var divide = createMathOperation(function (dividend, divisor) {
                                return dividend / divisor;
                            }, 1);

                            /**
                             * Computes `number` rounded down to `precision`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.10.0
                             * @category Math
                             * @param {number} number The number to round down.
                             * @param {number} [precision=0] The precision to round down to.
                             * @returns {number} Returns the rounded down number.
                             * @example
                             *
                             * _.floor(4.006);
                             * // => 4
                             *
                             * _.floor(0.046, 2);
                             * // => 0.04
                             *
                             * _.floor(4060, -2);
                             * // => 4000
                             */
                            var floor = createRound('floor');

                            /**
                             * Computes the maximum value of `array`. If `array` is empty or falsey,
                             * `undefined` is returned.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Math
                             * @param {Array} array The array to iterate over.
                             * @returns {*} Returns the maximum value.
                             * @example
                             *
                             * _.max([4, 2, 8, 6]);
                             * // => 8
                             *
                             * _.max([]);
                             * // => undefined
                             */
                            function max(array) {
                                return (array && array.length)
                                    ? baseExtremum(array, identity, baseGt)
                                    : undefined;
                            }

                            /**
                             * This method is like `_.max` except that it accepts `iteratee` which is
                             * invoked for each element in `array` to generate the criterion by which
                             * the value is ranked. The iteratee is invoked with one argument: (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Math
                             * @param {Array} array The array to iterate over.
                             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
                             * @returns {*} Returns the maximum value.
                             * @example
                             *
                             * var objects = [{ 'n': 1 }, { 'n': 2 }];
                             *
                             * _.maxBy(objects, function(o) { return o.n; });
                             * // => { 'n': 2 }
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.maxBy(objects, 'n');
                             * // => { 'n': 2 }
                             */
                            function maxBy(array, iteratee) {
                                return (array && array.length)
                                    ? baseExtremum(array, getIteratee(iteratee, 2), baseGt)
                                    : undefined;
                            }

                            /**
                             * Computes the mean of the values in `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Math
                             * @param {Array} array The array to iterate over.
                             * @returns {number} Returns the mean.
                             * @example
                             *
                             * _.mean([4, 2, 8, 6]);
                             * // => 5
                             */
                            function mean(array) {
                                return baseMean(array, identity);
                            }

                            /**
                             * This method is like `_.mean` except that it accepts `iteratee` which is
                             * invoked for each element in `array` to generate the value to be averaged.
                             * The iteratee is invoked with one argument: (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.7.0
                             * @category Math
                             * @param {Array} array The array to iterate over.
                             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
                             * @returns {number} Returns the mean.
                             * @example
                             *
                             * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
                             *
                             * _.meanBy(objects, function(o) { return o.n; });
                             * // => 5
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.meanBy(objects, 'n');
                             * // => 5
                             */
                            function meanBy(array, iteratee) {
                                return baseMean(array, getIteratee(iteratee, 2));
                            }

                            /**
                             * Computes the minimum value of `array`. If `array` is empty or falsey,
                             * `undefined` is returned.
                             *
                             * @static
                             * @since 0.1.0
                             * @memberOf _
                             * @category Math
                             * @param {Array} array The array to iterate over.
                             * @returns {*} Returns the minimum value.
                             * @example
                             *
                             * _.min([4, 2, 8, 6]);
                             * // => 2
                             *
                             * _.min([]);
                             * // => undefined
                             */
                            function min(array) {
                                return (array && array.length)
                                    ? baseExtremum(array, identity, baseLt)
                                    : undefined;
                            }

                            /**
                             * This method is like `_.min` except that it accepts `iteratee` which is
                             * invoked for each element in `array` to generate the criterion by which
                             * the value is ranked. The iteratee is invoked with one argument: (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Math
                             * @param {Array} array The array to iterate over.
                             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
                             * @returns {*} Returns the minimum value.
                             * @example
                             *
                             * var objects = [{ 'n': 1 }, { 'n': 2 }];
                             *
                             * _.minBy(objects, function(o) { return o.n; });
                             * // => { 'n': 1 }
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.minBy(objects, 'n');
                             * // => { 'n': 1 }
                             */
                            function minBy(array, iteratee) {
                                return (array && array.length)
                                    ? baseExtremum(array, getIteratee(iteratee, 2), baseLt)
                                    : undefined;
                            }

                            /**
                             * Multiply two numbers.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.7.0
                             * @category Math
                             * @param {number} multiplier The first number in a multiplication.
                             * @param {number} multiplicand The second number in a multiplication.
                             * @returns {number} Returns the product.
                             * @example
                             *
                             * _.multiply(6, 4);
                             * // => 24
                             */
                            var multiply = createMathOperation(function (multiplier, multiplicand) {
                                return multiplier * multiplicand;
                            }, 1);

                            /**
                             * Computes `number` rounded to `precision`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.10.0
                             * @category Math
                             * @param {number} number The number to round.
                             * @param {number} [precision=0] The precision to round to.
                             * @returns {number} Returns the rounded number.
                             * @example
                             *
                             * _.round(4.006);
                             * // => 4
                             *
                             * _.round(4.006, 2);
                             * // => 4.01
                             *
                             * _.round(4060, -2);
                             * // => 4100
                             */
                            var round = createRound('round');

                            /**
                             * Subtract two numbers.
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Math
                             * @param {number} minuend The first number in a subtraction.
                             * @param {number} subtrahend The second number in a subtraction.
                             * @returns {number} Returns the difference.
                             * @example
                             *
                             * _.subtract(6, 4);
                             * // => 2
                             */
                            var subtract = createMathOperation(function (minuend, subtrahend) {
                                return minuend - subtrahend;
                            }, 0);

                            /**
                             * Computes the sum of the values in `array`.
                             *
                             * @static
                             * @memberOf _
                             * @since 3.4.0
                             * @category Math
                             * @param {Array} array The array to iterate over.
                             * @returns {number} Returns the sum.
                             * @example
                             *
                             * _.sum([4, 2, 8, 6]);
                             * // => 20
                             */
                            function sum(array) {
                                return (array && array.length)
                                    ? baseSum(array, identity)
                                    : 0;
                            }

                            /**
                             * This method is like `_.sum` except that it accepts `iteratee` which is
                             * invoked for each element in `array` to generate the value to be summed.
                             * The iteratee is invoked with one argument: (value).
                             *
                             * @static
                             * @memberOf _
                             * @since 4.0.0
                             * @category Math
                             * @param {Array} array The array to iterate over.
                             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
                             * @returns {number} Returns the sum.
                             * @example
                             *
                             * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
                             *
                             * _.sumBy(objects, function(o) { return o.n; });
                             * // => 20
                             *
                             * // The `_.property` iteratee shorthand.
                             * _.sumBy(objects, 'n');
                             * // => 20
                             */
                            function sumBy(array, iteratee) {
                                return (array && array.length)
                                    ? baseSum(array, getIteratee(iteratee, 2))
                                    : 0;
                            }

                            /*------------------------------------------------------------------------*/

                            // Add methods that return wrapped values in chain sequences.
                            lodash.after = after;
                            lodash.ary = ary;
                            lodash.assign = assign;
                            lodash.assignIn = assignIn;
                            lodash.assignInWith = assignInWith;
                            lodash.assignWith = assignWith;
                            lodash.at = at;
                            lodash.before = before;
                            lodash.bind = bind;
                            lodash.bindAll = bindAll;
                            lodash.bindKey = bindKey;
                            lodash.castArray = castArray;
                            lodash.chain = chain;
                            lodash.chunk = chunk;
                            lodash.compact = compact;
                            lodash.concat = concat;
                            lodash.cond = cond;
                            lodash.conforms = conforms;
                            lodash.constant = constant;
                            lodash.countBy = countBy;
                            lodash.create = create;
                            lodash.curry = curry;
                            lodash.curryRight = curryRight;
                            lodash.debounce = debounce;
                            lodash.defaults = defaults;
                            lodash.defaultsDeep = defaultsDeep;
                            lodash.defer = defer;
                            lodash.delay = delay;
                            lodash.difference = difference;
                            lodash.differenceBy = differenceBy;
                            lodash.differenceWith = differenceWith;
                            lodash.drop = drop;
                            lodash.dropRight = dropRight;
                            lodash.dropRightWhile = dropRightWhile;
                            lodash.dropWhile = dropWhile;
                            lodash.fill = fill;
                            lodash.filter = filter;
                            lodash.flatMap = flatMap;
                            lodash.flatMapDeep = flatMapDeep;
                            lodash.flatMapDepth = flatMapDepth;
                            lodash.flatten = flatten;
                            lodash.flattenDeep = flattenDeep;
                            lodash.flattenDepth = flattenDepth;
                            lodash.flip = flip;
                            lodash.flow = flow;
                            lodash.flowRight = flowRight;
                            lodash.fromPairs = fromPairs;
                            lodash.functions = functions;
                            lodash.functionsIn = functionsIn;
                            lodash.groupBy = groupBy;
                            lodash.initial = initial;
                            lodash.intersection = intersection;
                            lodash.intersectionBy = intersectionBy;
                            lodash.intersectionWith = intersectionWith;
                            lodash.invert = invert;
                            lodash.invertBy = invertBy;
                            lodash.invokeMap = invokeMap;
                            lodash.iteratee = iteratee;
                            lodash.keyBy = keyBy;
                            lodash.keys = keys;
                            lodash.keysIn = keysIn;
                            lodash.map = map;
                            lodash.mapKeys = mapKeys;
                            lodash.mapValues = mapValues;
                            lodash.matches = matches;
                            lodash.matchesProperty = matchesProperty;
                            lodash.memoize = memoize;
                            lodash.merge = merge;
                            lodash.mergeWith = mergeWith;
                            lodash.method = method;
                            lodash.methodOf = methodOf;
                            lodash.mixin = mixin;
                            lodash.negate = negate;
                            lodash.nthArg = nthArg;
                            lodash.omit = omit;
                            lodash.omitBy = omitBy;
                            lodash.once = once;
                            lodash.orderBy = orderBy;
                            lodash.over = over;
                            lodash.overArgs = overArgs;
                            lodash.overEvery = overEvery;
                            lodash.overSome = overSome;
                            lodash.partial = partial;
                            lodash.partialRight = partialRight;
                            lodash.partition = partition;
                            lodash.pick = pick;
                            lodash.pickBy = pickBy;
                            lodash.property = property;
                            lodash.propertyOf = propertyOf;
                            lodash.pull = pull;
                            lodash.pullAll = pullAll;
                            lodash.pullAllBy = pullAllBy;
                            lodash.pullAllWith = pullAllWith;
                            lodash.pullAt = pullAt;
                            lodash.range = range;
                            lodash.rangeRight = rangeRight;
                            lodash.rearg = rearg;
                            lodash.reject = reject;
                            lodash.remove = remove;
                            lodash.rest = rest;
                            lodash.reverse = reverse;
                            lodash.sampleSize = sampleSize;
                            lodash.set = set;
                            lodash.setWith = setWith;
                            lodash.shuffle = shuffle;
                            lodash.slice = slice;
                            lodash.sortBy = sortBy;
                            lodash.sortedUniq = sortedUniq;
                            lodash.sortedUniqBy = sortedUniqBy;
                            lodash.split = split;
                            lodash.spread = spread;
                            lodash.tail = tail;
                            lodash.take = take;
                            lodash.takeRight = takeRight;
                            lodash.takeRightWhile = takeRightWhile;
                            lodash.takeWhile = takeWhile;
                            lodash.tap = tap;
                            lodash.throttle = throttle;
                            lodash.thru = thru;
                            lodash.toArray = toArray;
                            lodash.toPairs = toPairs;
                            lodash.toPairsIn = toPairsIn;
                            lodash.toPath = toPath;
                            lodash.toPlainObject = toPlainObject;
                            lodash.transform = transform;
                            lodash.unary = unary;
                            lodash.union = union;
                            lodash.unionBy = unionBy;
                            lodash.unionWith = unionWith;
                            lodash.uniq = uniq;
                            lodash.uniqBy = uniqBy;
                            lodash.uniqWith = uniqWith;
                            lodash.unset = unset;
                            lodash.unzip = unzip;
                            lodash.unzipWith = unzipWith;
                            lodash.update = update;
                            lodash.updateWith = updateWith;
                            lodash.values = values;
                            lodash.valuesIn = valuesIn;
                            lodash.without = without;
                            lodash.words = words;
                            lodash.wrap = wrap;
                            lodash.xor = xor;
                            lodash.xorBy = xorBy;
                            lodash.xorWith = xorWith;
                            lodash.zip = zip;
                            lodash.zipObject = zipObject;
                            lodash.zipObjectDeep = zipObjectDeep;
                            lodash.zipWith = zipWith;

                            // Add aliases.
                            lodash.entries = toPairs;
                            lodash.entriesIn = toPairsIn;
                            lodash.extend = assignIn;
                            lodash.extendWith = assignInWith;

                            // Add methods to `lodash.prototype`.
                            mixin(lodash, lodash);

                            /*------------------------------------------------------------------------*/

                            // Add methods that return unwrapped values in chain sequences.
                            lodash.add = add;
                            lodash.attempt = attempt;
                            lodash.camelCase = camelCase;
                            lodash.capitalize = capitalize;
                            lodash.ceil = ceil;
                            lodash.clamp = clamp;
                            lodash.clone = clone;
                            lodash.cloneDeep = cloneDeep;
                            lodash.cloneDeepWith = cloneDeepWith;
                            lodash.cloneWith = cloneWith;
                            lodash.conformsTo = conformsTo;
                            lodash.deburr = deburr;
                            lodash.defaultTo = defaultTo;
                            lodash.divide = divide;
                            lodash.endsWith = endsWith;
                            lodash.eq = eq;
                            lodash.escape = escape;
                            lodash.escapeRegExp = escapeRegExp;
                            lodash.every = every;
                            lodash.find = find;
                            lodash.findIndex = findIndex;
                            lodash.findKey = findKey;
                            lodash.findLast = findLast;
                            lodash.findLastIndex = findLastIndex;
                            lodash.findLastKey = findLastKey;
                            lodash.floor = floor;
                            lodash.forEach = forEach;
                            lodash.forEachRight = forEachRight;
                            lodash.forIn = forIn;
                            lodash.forInRight = forInRight;
                            lodash.forOwn = forOwn;
                            lodash.forOwnRight = forOwnRight;
                            lodash.get = get;
                            lodash.gt = gt;
                            lodash.gte = gte;
                            lodash.has = has;
                            lodash.hasIn = hasIn;
                            lodash.head = head;
                            lodash.identity = identity;
                            lodash.includes = includes;
                            lodash.indexOf = indexOf;
                            lodash.inRange = inRange;
                            lodash.invoke = invoke;
                            lodash.isArguments = isArguments;
                            lodash.isArray = isArray;
                            lodash.isArrayBuffer = isArrayBuffer;
                            lodash.isArrayLike = isArrayLike;
                            lodash.isArrayLikeObject = isArrayLikeObject;
                            lodash.isBoolean = isBoolean;
                            lodash.isBuffer = isBuffer;
                            lodash.isDate = isDate;
                            lodash.isElement = isElement;
                            lodash.isEmpty = isEmpty;
                            lodash.isEqual = isEqual;
                            lodash.isEqualWith = isEqualWith;
                            lodash.isError = isError;
                            lodash.isFinite = isFinite;
                            lodash.isFunction = isFunction;
                            lodash.isInteger = isInteger;
                            lodash.isLength = isLength;
                            lodash.isMap = isMap;
                            lodash.isMatch = isMatch;
                            lodash.isMatchWith = isMatchWith;
                            lodash.isNaN = isNaN;
                            lodash.isNative = isNative;
                            lodash.isNil = isNil;
                            lodash.isNull = isNull;
                            lodash.isNumber = isNumber;
                            lodash.isObject = isObject;
                            lodash.isObjectLike = isObjectLike;
                            lodash.isPlainObject = isPlainObject;
                            lodash.isRegExp = isRegExp;
                            lodash.isSafeInteger = isSafeInteger;
                            lodash.isSet = isSet;
                            lodash.isString = isString;
                            lodash.isSymbol = isSymbol;
                            lodash.isTypedArray = isTypedArray;
                            lodash.isUndefined = isUndefined;
                            lodash.isWeakMap = isWeakMap;
                            lodash.isWeakSet = isWeakSet;
                            lodash.join = join;
                            lodash.kebabCase = kebabCase;
                            lodash.last = last;
                            lodash.lastIndexOf = lastIndexOf;
                            lodash.lowerCase = lowerCase;
                            lodash.lowerFirst = lowerFirst;
                            lodash.lt = lt;
                            lodash.lte = lte;
                            lodash.max = max;
                            lodash.maxBy = maxBy;
                            lodash.mean = mean;
                            lodash.meanBy = meanBy;
                            lodash.min = min;
                            lodash.minBy = minBy;
                            lodash.stubArray = stubArray;
                            lodash.stubFalse = stubFalse;
                            lodash.stubObject = stubObject;
                            lodash.stubString = stubString;
                            lodash.stubTrue = stubTrue;
                            lodash.multiply = multiply;
                            lodash.nth = nth;
                            lodash.noConflict = noConflict;
                            lodash.noop = noop;
                            lodash.now = now;
                            lodash.pad = pad;
                            lodash.padEnd = padEnd;
                            lodash.padStart = padStart;
                            lodash.parseInt = parseInt;
                            lodash.random = random;
                            lodash.reduce = reduce;
                            lodash.reduceRight = reduceRight;
                            lodash.repeat = repeat;
                            lodash.replace = replace;
                            lodash.result = result;
                            lodash.round = round;
                            lodash.runInContext = runInContext;
                            lodash.sample = sample;
                            lodash.size = size;
                            lodash.snakeCase = snakeCase;
                            lodash.some = some;
                            lodash.sortedIndex = sortedIndex;
                            lodash.sortedIndexBy = sortedIndexBy;
                            lodash.sortedIndexOf = sortedIndexOf;
                            lodash.sortedLastIndex = sortedLastIndex;
                            lodash.sortedLastIndexBy = sortedLastIndexBy;
                            lodash.sortedLastIndexOf = sortedLastIndexOf;
                            lodash.startCase = startCase;
                            lodash.startsWith = startsWith;
                            lodash.subtract = subtract;
                            lodash.sum = sum;
                            lodash.sumBy = sumBy;
                            lodash.template = template;
                            lodash.times = times;
                            lodash.toFinite = toFinite;
                            lodash.toInteger = toInteger;
                            lodash.toLength = toLength;
                            lodash.toLower = toLower;
                            lodash.toNumber = toNumber;
                            lodash.toSafeInteger = toSafeInteger;
                            lodash.toString = toString;
                            lodash.toUpper = toUpper;
                            lodash.trim = trim;
                            lodash.trimEnd = trimEnd;
                            lodash.trimStart = trimStart;
                            lodash.truncate = truncate;
                            lodash.unescape = unescape;
                            lodash.uniqueId = uniqueId;
                            lodash.upperCase = upperCase;
                            lodash.upperFirst = upperFirst;

                            // Add aliases.
                            lodash.each = forEach;
                            lodash.eachRight = forEachRight;
                            lodash.first = head;

                            mixin(lodash, (function () {
                                var source = {};
                                baseForOwn(lodash, function (func, methodName) {
                                    if (!hasOwnProperty.call(lodash.prototype, methodName)) {
                                        source[methodName] = func;
                                    }
                                });
                                return source;
                            }()), { 'chain': false });

                            /*------------------------------------------------------------------------*/

                            /**
                             * The semantic version number.
                             *
                             * @static
                             * @memberOf _
                             * @type {string}
                             */
                            lodash.VERSION = VERSION;

                            // Assign default placeholders.
                            arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function (methodName) {
                                lodash[methodName].placeholder = lodash;
                            });

                            // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
                            arrayEach(['drop', 'take'], function (methodName, index) {
                                LazyWrapper.prototype[methodName] = function (n) {
                                    n = n === undefined ? 1 : nativeMax(toInteger(n), 0);

                                    var result = (this.__filtered__ && !index)
                                        ? new LazyWrapper(this)
                                        : this.clone();

                                    if (result.__filtered__) {
                                        result.__takeCount__ = nativeMin(n, result.__takeCount__);
                                    } else {
                                        result.__views__.push({
                                            'size': nativeMin(n, MAX_ARRAY_LENGTH),
                                            'type': methodName + (result.__dir__ < 0 ? 'Right' : '')
                                        });
                                    }
                                    return result;
                                };

                                LazyWrapper.prototype[methodName + 'Right'] = function (n) {
                                    return this.reverse()[methodName](n).reverse();
                                };
                            });

                            // Add `LazyWrapper` methods that accept an `iteratee` value.
                            arrayEach(['filter', 'map', 'takeWhile'], function (methodName, index) {
                                var type = index + 1,
                                    isFilter = type == LAZY_FILTER_FLAG || type == LAZY_WHILE_FLAG;

                                LazyWrapper.prototype[methodName] = function (iteratee) {
                                    var result = this.clone();
                                    result.__iteratees__.push({
                                        'iteratee': getIteratee(iteratee, 3),
                                        'type': type
                                    });
                                    result.__filtered__ = result.__filtered__ || isFilter;
                                    return result;
                                };
                            });

                            // Add `LazyWrapper` methods for `_.head` and `_.last`.
                            arrayEach(['head', 'last'], function (methodName, index) {
                                var takeName = 'take' + (index ? 'Right' : '');

                                LazyWrapper.prototype[methodName] = function () {
                                    return this[takeName](1).value()[0];
                                };
                            });

                            // Add `LazyWrapper` methods for `_.initial` and `_.tail`.
                            arrayEach(['initial', 'tail'], function (methodName, index) {
                                var dropName = 'drop' + (index ? '' : 'Right');

                                LazyWrapper.prototype[methodName] = function () {
                                    return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1);
                                };
                            });

                            LazyWrapper.prototype.compact = function () {
                                return this.filter(identity);
                            };

                            LazyWrapper.prototype.find = function (predicate) {
                                return this.filter(predicate).head();
                            };

                            LazyWrapper.prototype.findLast = function (predicate) {
                                return this.reverse().find(predicate);
                            };

                            LazyWrapper.prototype.invokeMap = baseRest(function (path, args) {
                                if (typeof path == 'function') {
                                    return new LazyWrapper(this);
                                }
                                return this.map(function (value) {
                                    return baseInvoke(value, path, args);
                                });
                            });

                            LazyWrapper.prototype.reject = function (predicate) {
                                return this.filter(negate(getIteratee(predicate)));
                            };

                            LazyWrapper.prototype.slice = function (start, end) {
                                start = toInteger(start);

                                var result = this;
                                if (result.__filtered__ && (start > 0 || end < 0)) {
                                    return new LazyWrapper(result);
                                }
                                if (start < 0) {
                                    result = result.takeRight(-start);
                                } else if (start) {
                                    result = result.drop(start);
                                }
                                if (end !== undefined) {
                                    end = toInteger(end);
                                    result = end < 0 ? result.dropRight(-end) : result.take(end - start);
                                }
                                return result;
                            };

                            LazyWrapper.prototype.takeRightWhile = function (predicate) {
                                return this.reverse().takeWhile(predicate).reverse();
                            };

                            LazyWrapper.prototype.toArray = function () {
                                return this.take(MAX_ARRAY_LENGTH);
                            };

                            // Add `LazyWrapper` methods to `lodash.prototype`.
                            baseForOwn(LazyWrapper.prototype, function (func, methodName) {
                                var checkIteratee = /^(?:filter|find|map|reject)|While$/.test(methodName),
                                    isTaker = /^(?:head|last)$/.test(methodName),
                                    lodashFunc = lodash[isTaker ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName],
                                    retUnwrapped = isTaker || /^find/.test(methodName);

                                if (!lodashFunc) {
                                    return;
                                }
                                lodash.prototype[methodName] = function () {
                                    var value = this.__wrapped__,
                                        args = isTaker ? [1] : arguments,
                                        isLazy = value instanceof LazyWrapper,
                                        iteratee = args[0],
                                        useLazy = isLazy || isArray(value);

                                    var interceptor = function (value) {
                                        var result = lodashFunc.apply(lodash, arrayPush([value], args));
                                        return (isTaker && chainAll) ? result[0] : result;
                                    };

                                    if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) {
                                        // Avoid lazy use if the iteratee has a "length" value other than `1`.
                                        isLazy = useLazy = false;
                                    }
                                    var chainAll = this.__chain__,
                                        isHybrid = !!this.__actions__.length,
                                        isUnwrapped = retUnwrapped && !chainAll,
                                        onlyLazy = isLazy && !isHybrid;

                                    if (!retUnwrapped && useLazy) {
                                        value = onlyLazy ? value : new LazyWrapper(this);
                                        var result = func.apply(value, args);
                                        result.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined });
                                        return new LodashWrapper(result, chainAll);
                                    }
                                    if (isUnwrapped && onlyLazy) {
                                        return func.apply(this, args);
                                    }
                                    result = this.thru(interceptor);
                                    return isUnwrapped ? (isTaker ? result.value()[0] : result.value()) : result;
                                };
                            });

                            // Add `Array` methods to `lodash.prototype`.
                            arrayEach(['pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function (methodName) {
                                var func = arrayProto[methodName],
                                    chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
                                    retUnwrapped = /^(?:pop|shift)$/.test(methodName);

                                lodash.prototype[methodName] = function () {
                                    var args = arguments;
                                    if (retUnwrapped && !this.__chain__) {
                                        var value = this.value();
                                        return func.apply(isArray(value) ? value : [], args);
                                    }
                                    return this[chainName](function (value) {
                                        return func.apply(isArray(value) ? value : [], args);
                                    });
                                };
                            });

                            // Map minified method names to their real names.
                            baseForOwn(LazyWrapper.prototype, function (func, methodName) {
                                var lodashFunc = lodash[methodName];
                                if (lodashFunc) {
                                    var key = lodashFunc.name + '';
                                    if (!hasOwnProperty.call(realNames, key)) {
                                        realNames[key] = [];
                                    }
                                    realNames[key].push({ 'name': methodName, 'func': lodashFunc });
                                }
                            });

                            realNames[createHybrid(undefined, WRAP_BIND_KEY_FLAG).name] = [{
                                'name': 'wrapper',
                                'func': undefined
                            }];

                            // Add methods to `LazyWrapper`.
                            LazyWrapper.prototype.clone = lazyClone;
                            LazyWrapper.prototype.reverse = lazyReverse;
                            LazyWrapper.prototype.value = lazyValue;

                            // Add chain sequence methods to the `lodash` wrapper.
                            lodash.prototype.at = wrapperAt;
                            lodash.prototype.chain = wrapperChain;
                            lodash.prototype.commit = wrapperCommit;
                            lodash.prototype.next = wrapperNext;
                            lodash.prototype.plant = wrapperPlant;
                            lodash.prototype.reverse = wrapperReverse;
                            lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;

                            // Add lazy aliases.
                            lodash.prototype.first = lodash.prototype.head;

                            if (symIterator) {
                                lodash.prototype[symIterator] = wrapperToIterator;
                            }
                            return lodash;
                        });

                        /*--------------------------------------------------------------------------*/

                        // Export lodash.
                        var _ = runInContext();

                        // Some AMD build optimizers, like r.js, check for condition patterns like:
                        if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
                            // Expose Lodash on the global object to prevent errors when Lodash is
                            // loaded by a script tag in the presence of an AMD loader.
                            // See http://requirejs.org/docs/errors.html#mismatch for more details.
                            // Use `_.noConflict` to remove Lodash from the global object.
                            root._ = _;

                            // Define as an anonymous module so, through path mapping, it can be
                            // referenced as the "underscore" module.
                            define(function () {
                                return _;
                            });
                        }
                        // Check for `exports` after `define` in case a build optimizer adds it.
                        else if (freeModule) {
                            // Export for Node.js.
                            (freeModule.exports = _)._ = _;
                            // Export for CommonJS support.
                            freeExports._ = _;
                        }
                        else {
                            // Export to the global object.
                            root._ = _;
                        }
                    }.call(this));

                }).call(this)
            }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
        }, {}], 103: [function (require, module, exports) {
            'use strict';

            const w3 = {
                svg: 'http://www.w3.org/2000/svg',
                xlink: 'http://www.w3.org/1999/xlink',
                xmlns: 'http://www.w3.org/XML/1998/namespace'
            };

            module.exports = (w, h) => ['svg', {
                xmlns: w3.svg, 'xmlns:xlink': w3.xlink,
                width: w, height: h,
                viewBox: '0 0 ' + w + ' ' + h
            }];

        }, {}], 104: [function (require, module, exports) {
            'use strict';

            const parse = require('./parse.js');
            const stringify = require('./stringify.js');
            const traverse = require('./traverse.js');
            const renderer = require('./renderer.js');
            const tt = require('./tt.js');
            const genSvg = require('./gen-svg.js');

            exports.renderer = renderer;
            exports.parse = parse;
            exports.stringify = stringify;
            exports.traverse = traverse;
            exports.tt = tt;

            exports.gen = {
                svg: genSvg
            };

            exports.p = parse;
            exports.s = stringify;
            exports.t = traverse;

        }, { "./gen-svg.js": 103, "./parse.js": 105, "./renderer.js": 106, "./stringify.js": 107, "./traverse.js": 108, "./tt.js": 109 }], 105: [function (require, module, exports) {
            'use strict';

            const parser = require('sax').parser;

            function parse(data, config) {
                const res = [];
                const stack = [];
                let pointer = res;
                let trim = true;

                let strict = true;
                if (config && (config.strict !== undefined)) {
                    strict = config.strict;
                }

                if (config !== undefined) {
                    if (config.trim !== undefined) {
                        trim = config.trim;
                    }
                }

                const p = parser(strict);

                p.ontext = function (e) {
                    if ((trim === false) || (e.trim() !== '')) {
                        pointer.push(e);
                    }
                };

                p.onopentag = function (e) {
                    const leaf = [e.name, e.attributes];
                    stack.push(pointer);
                    pointer.push(leaf);
                    pointer = leaf;
                };

                p.onclosetag = function () {
                    pointer = stack.pop();
                };

                p.oncdata = function (e) {
                    if ((trim === false) || (e.trim() !== '')) {
                        pointer.push('<![CDATA[' + e + ']]>');
                    }
                };

                p.write(data).close();
                return res[0];
            }

            module.exports = parse;

        }, { "sax": 110 }], 106: [function (require, module, exports) {
            'use strict';

            const stringify = require('./stringify.js');

            const renderer = root => {
                const content = (typeof root === 'string')
                    ? document.getElementById(root)
                    : root;

                return ml => {
                    let str;
                    try {
                        str = stringify(ml);
                        content.innerHTML = str;
                    } catch (err) {
                        console.log(ml);
                    }
                };
            };

            module.exports = renderer;

            /* eslint-env browser */

        }, { "./stringify.js": 107 }], 107: [function (require, module, exports) {
            'use strict';

            const isObject = o => o && Object.prototype.toString.call(o) === '[object Object]';

            function indenter(indentation) {
                if (!(indentation > 0)) {
                    return txt => txt;
                }
                var space = ' '.repeat(indentation);
                return txt => {

                    if (typeof txt !== 'string') {
                        return txt;
                    }

                    const arr = txt.split('\n');

                    if (arr.length === 1) {
                        return space + txt;
                    }

                    return arr
                        .map(e => (e.trim() === '') ? e : space + e)
                        .join('\n');
                };
            }

            const clean = txt => txt
                .split('\n')
                .filter(e => e.trim() !== '')
                .join('\n');

            function stringify(a, indentation) {
                const cr = (indentation > 0) ? '\n' : '';
                const indent = indenter(indentation);

                function rec(a) {
                    let body = '';
                    let isFlat = true;

                    let res;
                    const isEmpty = a.some((e, i, arr) => {
                        if (i === 0) {
                            res = '<' + e;
                            return (arr.length === 1);
                        }

                        if (i === 1) {
                            if (isObject(e)) {
                                Object.keys(e).map(key => {
                                    let val = e[key];
                                    if (Array.isArray(val)) {
                                        val = val.join(' ');
                                    }
                                    res += ' ' + key + '="' + val + '"';
                                });
                                if (arr.length === 2) {
                                    return true;
                                }
                                res += '>';
                                return;
                            }
                            res += '>';
                        }

                        switch (typeof e) {
                            case 'string':
                            case 'number':
                            case 'boolean':
                            case 'undefined':
                                body += e + cr;
                                return;
                        }

                        isFlat = false;
                        body += rec(e);
                    });

                    if (isEmpty) {
                        return res + '/>' + cr; // short form
                    }

                    return isFlat
                        ? res + clean(body) + '</' + a[0] + '>' + cr
                        : res + cr + indent(body) + '</' + a[0] + '>' + cr;
                }

                return rec(a);
            }

            module.exports = stringify;

        }, {}], 108: [function (require, module, exports) {
            'use strict';

            function skipFn() {
                this._skip = true;
            }

            function removeFn() {
                this._remove = true;
            }

            function nameFn(name) {
                this._name = name;
            }

            function replaceFn(node) {
                this._replace = node;
            }

            function traverse(origin, callbacks) {
                const empty = function () { };

                const enter = callbacks && callbacks.enter || empty;
                const leave = callbacks && callbacks.leave || empty;


                function rec(tree, parent) {
                    if (tree === undefined) return;
                    if (tree === null) return;
                    if (tree === true) return;
                    if (tree === false) return;

                    const node = {
                        attr: {},
                        full: tree
                    };

                    const cxt = {
                        name: nameFn,
                        skip: skipFn,
                        // break: breakFn,
                        remove: removeFn,
                        replace: replaceFn,

                        _name: undefined,
                        _skip: false,
                        // _break: false,
                        _remove: false,
                        _replace: undefined
                    };

                    let e1IsNotAnObject = true;

                    switch (Object.prototype.toString.call(tree)) {
                        case '[object String]':
                        case '[object Number]':
                            return;

                        case '[object Array]':
                            tree.some(function (e, i) {
                                if (i === 0) {
                                    node.name = e;
                                    return false;
                                }
                                if (i === 1) {
                                    if (
                                        Object.prototype.toString.call(e) === '[object Object]'
                                    ) {
                                        e1IsNotAnObject = false;
                                        node.attr = e;
                                    }
                                    return true;
                                }
                            });

                            enter.call(cxt, node, parent);

                            if (cxt._name) {
                                tree[0] = cxt._name;
                            }

                            if (cxt._replace) {
                                return cxt._replace;
                            }

                            if (cxt._remove) {
                                return null;
                            }

                            if (!cxt._skip) {
                                let index = 0;
                                let ilen = tree.length;
                                while (index < ilen) {
                                    if ((index > 1) || ((index === 1) && e1IsNotAnObject)) {
                                        const returnRes = rec(tree[index], node);
                                        if (returnRes === null) {
                                            tree.splice(index, 1);
                                            ilen -= 1;
                                            continue;
                                        }
                                        if (returnRes) {
                                            tree[index] = returnRes;
                                        }
                                    }
                                    index += 1;
                                }

                                leave.call(cxt, node, parent);
                                if (cxt._name) {
                                    tree[0] = cxt._name;
                                }
                                if (cxt._replace) {
                                    return cxt._replace;
                                }
                                if (cxt._remove) {
                                    return null;
                                }
                            }
                    }
                }

                rec(origin, undefined);
            }

            module.exports = traverse;

            /* eslint complexity: 0 */

        }, {}], 109: [function (require, module, exports) {
            'use strict';

            module.exports = (x, y, obj) => {
                let objt = {};
                if (x || y) {
                    const tt = [x || 0].concat(y ? [y] : []);
                    objt = { transform: 'translate(' + tt.join(',') + ')' };
                }
                obj = (typeof obj === 'object') ? obj : {};
                return Object.assign(objt, obj);
            };

        }, {}], 110: [function (require, module, exports) {
            (function (Buffer) {
                (function () {
                    ; (function (sax) { // wrapper for non-node envs
                        sax.parser = function (strict, opt) { return new SAXParser(strict, opt) }
                        sax.SAXParser = SAXParser
                        sax.SAXStream = SAXStream
                        sax.createStream = createStream

                        // When we pass the MAX_BUFFER_LENGTH position, start checking for buffer overruns.
                        // When we check, schedule the next check for MAX_BUFFER_LENGTH - (max(buffer lengths)),
                        // since that's the earliest that a buffer overrun could occur.  This way, checks are
                        // as rare as required, but as often as necessary to ensure never crossing this bound.
                        // Furthermore, buffers are only tested at most once per write(), so passing a very
                        // large string into write() might have undesirable effects, but this is manageable by
                        // the caller, so it is assumed to be safe.  Thus, a call to write() may, in the extreme
                        // edge case, result in creating at most one complete copy of the string passed in.
                        // Set to Infinity to have unlimited buffers.
                        sax.MAX_BUFFER_LENGTH = 64 * 1024

                        var buffers = [
                            'comment', 'sgmlDecl', 'textNode', 'tagName', 'doctype',
                            'procInstName', 'procInstBody', 'entity', 'attribName',
                            'attribValue', 'cdata', 'script'
                        ]

                        sax.EVENTS = [
                            'text',
                            'processinginstruction',
                            'sgmldeclaration',
                            'doctype',
                            'comment',
                            'opentagstart',
                            'attribute',
                            'opentag',
                            'closetag',
                            'opencdata',
                            'cdata',
                            'closecdata',
                            'error',
                            'end',
                            'ready',
                            'script',
                            'opennamespace',
                            'closenamespace'
                        ]

                        function SAXParser(strict, opt) {
                            if (!(this instanceof SAXParser)) {
                                return new SAXParser(strict, opt)
                            }

                            var parser = this
                            clearBuffers(parser)
                            parser.q = parser.c = ''
                            parser.bufferCheckPosition = sax.MAX_BUFFER_LENGTH
                            parser.opt = opt || {}
                            parser.opt.lowercase = parser.opt.lowercase || parser.opt.lowercasetags
                            parser.looseCase = parser.opt.lowercase ? 'toLowerCase' : 'toUpperCase'
                            parser.tags = []
                            parser.closed = parser.closedRoot = parser.sawRoot = false
                            parser.tag = parser.error = null
                            parser.strict = !!strict
                            parser.noscript = !!(strict || parser.opt.noscript)
                            parser.state = S.BEGIN
                            parser.strictEntities = parser.opt.strictEntities
                            parser.ENTITIES = parser.strictEntities ? Object.create(sax.XML_ENTITIES) : Object.create(sax.ENTITIES)
                            parser.attribList = []

                            // namespaces form a prototype chain.
                            // it always points at the current tag,
                            // which protos to its parent tag.
                            if (parser.opt.xmlns) {
                                parser.ns = Object.create(rootNS)
                            }

                            // mostly just for error reporting
                            parser.trackPosition = parser.opt.position !== false
                            if (parser.trackPosition) {
                                parser.position = parser.line = parser.column = 0
                            }
                            emit(parser, 'onready')
                        }

                        if (!Object.create) {
                            Object.create = function (o) {
                                function F() { }
                                F.prototype = o
                                var newf = new F()
                                return newf
                            }
                        }

                        if (!Object.keys) {
                            Object.keys = function (o) {
                                var a = []
                                for (var i in o) if (o.hasOwnProperty(i)) a.push(i)
                                return a
                            }
                        }

                        function checkBufferLength(parser) {
                            var maxAllowed = Math.max(sax.MAX_BUFFER_LENGTH, 10)
                            var maxActual = 0
                            for (var i = 0, l = buffers.length; i < l; i++) {
                                var len = parser[buffers[i]].length
                                if (len > maxAllowed) {
                                    // Text/cdata nodes can get big, and since they're buffered,
                                    // we can get here under normal conditions.
                                    // Avoid issues by emitting the text node now,
                                    // so at least it won't get any bigger.
                                    switch (buffers[i]) {
                                        case 'textNode':
                                            closeText(parser)
                                            break

                                        case 'cdata':
                                            emitNode(parser, 'oncdata', parser.cdata)
                                            parser.cdata = ''
                                            break

                                        case 'script':
                                            emitNode(parser, 'onscript', parser.script)
                                            parser.script = ''
                                            break

                                        default:
                                            error(parser, 'Max buffer length exceeded: ' + buffers[i])
                                    }
                                }
                                maxActual = Math.max(maxActual, len)
                            }
                            // schedule the next check for the earliest possible buffer overrun.
                            var m = sax.MAX_BUFFER_LENGTH - maxActual
                            parser.bufferCheckPosition = m + parser.position
                        }

                        function clearBuffers(parser) {
                            for (var i = 0, l = buffers.length; i < l; i++) {
                                parser[buffers[i]] = ''
                            }
                        }

                        function flushBuffers(parser) {
                            closeText(parser)
                            if (parser.cdata !== '') {
                                emitNode(parser, 'oncdata', parser.cdata)
                                parser.cdata = ''
                            }
                            if (parser.script !== '') {
                                emitNode(parser, 'onscript', parser.script)
                                parser.script = ''
                            }
                        }

                        SAXParser.prototype = {
                            end: function () { end(this) },
                            write: write,
                            resume: function () { this.error = null; return this },
                            close: function () { return this.write(null) },
                            flush: function () { flushBuffers(this) }
                        }

                        var Stream
                        try {
                            Stream = require('stream').Stream
                        } catch (ex) {
                            Stream = function () { }
                        }

                        var streamWraps = sax.EVENTS.filter(function (ev) {
                            return ev !== 'error' && ev !== 'end'
                        })

                        function createStream(strict, opt) {
                            return new SAXStream(strict, opt)
                        }

                        function SAXStream(strict, opt) {
                            if (!(this instanceof SAXStream)) {
                                return new SAXStream(strict, opt)
                            }

                            Stream.apply(this)

                            this._parser = new SAXParser(strict, opt)
                            this.writable = true
                            this.readable = true

                            var me = this

                            this._parser.onend = function () {
                                me.emit('end')
                            }

                            this._parser.onerror = function (er) {
                                me.emit('error', er)

                                // if didn't throw, then means error was handled.
                                // go ahead and clear error, so we can write again.
                                me._parser.error = null
                            }

                            this._decoder = null

                            streamWraps.forEach(function (ev) {
                                Object.defineProperty(me, 'on' + ev, {
                                    get: function () {
                                        return me._parser['on' + ev]
                                    },
                                    set: function (h) {
                                        if (!h) {
                                            me.removeAllListeners(ev)
                                            me._parser['on' + ev] = h
                                            return h
                                        }
                                        me.on(ev, h)
                                    },
                                    enumerable: true,
                                    configurable: false
                                })
                            })
                        }

                        SAXStream.prototype = Object.create(Stream.prototype, {
                            constructor: {
                                value: SAXStream
                            }
                        })

                        SAXStream.prototype.write = function (data) {
                            if (typeof Buffer === 'function' &&
                                typeof Buffer.isBuffer === 'function' &&
                                Buffer.isBuffer(data)) {
                                if (!this._decoder) {
                                    var SD = require('string_decoder').StringDecoder
                                    this._decoder = new SD('utf8')
                                }
                                data = this._decoder.write(data)
                            }

                            this._parser.write(data.toString())
                            this.emit('data', data)
                            return true
                        }

                        SAXStream.prototype.end = function (chunk) {
                            if (chunk && chunk.length) {
                                this.write(chunk)
                            }
                            this._parser.end()
                            return true
                        }

                        SAXStream.prototype.on = function (ev, handler) {
                            var me = this
                            if (!me._parser['on' + ev] && streamWraps.indexOf(ev) !== -1) {
                                me._parser['on' + ev] = function () {
                                    var args = arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments)
                                    args.splice(0, 0, ev)
                                    me.emit.apply(me, args)
                                }
                            }

                            return Stream.prototype.on.call(me, ev, handler)
                        }

                        // this really needs to be replaced with character classes.
                        // XML allows all manner of ridiculous numbers and digits.
                        var CDATA = '[CDATA['
                        var DOCTYPE = 'DOCTYPE'
                        var XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace'
                        var XMLNS_NAMESPACE = 'http://www.w3.org/2000/xmlns/'
                        var rootNS = { xml: XML_NAMESPACE, xmlns: XMLNS_NAMESPACE }

                        // http://www.w3.org/TR/REC-xml/#NT-NameStartChar
                        // This implementation works on strings, a single character at a time
                        // as such, it cannot ever support astral-plane characters (10000-EFFFF)
                        // without a significant breaking change to either this  parser, or the
                        // JavaScript language.  Implementation of an emoji-capable xml parser
                        // is left as an exercise for the reader.
                        var nameStart = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/

                        var nameBody = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/

                        var entityStart = /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/
                        var entityBody = /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/

                        function isWhitespace(c) {
                            return c === ' ' || c === '\n' || c === '\r' || c === '\t'
                        }

                        function isQuote(c) {
                            return c === '"' || c === '\''
                        }

                        function isAttribEnd(c) {
                            return c === '>' || isWhitespace(c)
                        }

                        function isMatch(regex, c) {
                            return regex.test(c)
                        }

                        function notMatch(regex, c) {
                            return !isMatch(regex, c)
                        }

                        var S = 0
                        sax.STATE = {
                            BEGIN: S++, // leading byte order mark or whitespace
                            BEGIN_WHITESPACE: S++, // leading whitespace
                            TEXT: S++, // general stuff
                            TEXT_ENTITY: S++, // &amp and such.
                            OPEN_WAKA: S++, // <
                            SGML_DECL: S++, // <!BLARG
                            SGML_DECL_QUOTED: S++, // <!BLARG foo "bar
                            DOCTYPE: S++, // <!DOCTYPE
                            DOCTYPE_QUOTED: S++, // <!DOCTYPE "//blah
                            DOCTYPE_DTD: S++, // <!DOCTYPE "//blah" [ ...
                            DOCTYPE_DTD_QUOTED: S++, // <!DOCTYPE "//blah" [ "foo
                            COMMENT_STARTING: S++, // <!-
                            COMMENT: S++, // <!--
                            COMMENT_ENDING: S++, // <!-- blah -
                            COMMENT_ENDED: S++, // <!-- blah --
                            CDATA: S++, // <![CDATA[ something
                            CDATA_ENDING: S++, // ]
                            CDATA_ENDING_2: S++, // ]]
                            PROC_INST: S++, // <?hi
                            PROC_INST_BODY: S++, // <?hi there
                            PROC_INST_ENDING: S++, // <?hi "there" ?
                            OPEN_TAG: S++, // <strong
                            OPEN_TAG_SLASH: S++, // <strong /
                            ATTRIB: S++, // <a
                            ATTRIB_NAME: S++, // <a foo
                            ATTRIB_NAME_SAW_WHITE: S++, // <a foo _
                            ATTRIB_VALUE: S++, // <a foo=
                            ATTRIB_VALUE_QUOTED: S++, // <a foo="bar
                            ATTRIB_VALUE_CLOSED: S++, // <a foo="bar"
                            ATTRIB_VALUE_UNQUOTED: S++, // <a foo=bar
                            ATTRIB_VALUE_ENTITY_Q: S++, // <foo bar="&quot;"
                            ATTRIB_VALUE_ENTITY_U: S++, // <foo bar=&quot
                            CLOSE_TAG: S++, // </a
                            CLOSE_TAG_SAW_WHITE: S++, // </a   >
                            SCRIPT: S++, // <script> ...
                            SCRIPT_ENDING: S++ // <script> ... <
                        }

                        sax.XML_ENTITIES = {
                            'amp': '&',
                            'gt': '>',
                            'lt': '<',
                            'quot': '"',
                            'apos': "'"
                        }

                        sax.ENTITIES = {
                            'amp': '&',
                            'gt': '>',
                            'lt': '<',
                            'quot': '"',
                            'apos': "'",
                            'AElig': 198,
                            'Aacute': 193,
                            'Acirc': 194,
                            'Agrave': 192,
                            'Aring': 197,
                            'Atilde': 195,
                            'Auml': 196,
                            'Ccedil': 199,
                            'ETH': 208,
                            'Eacute': 201,
                            'Ecirc': 202,
                            'Egrave': 200,
                            'Euml': 203,
                            'Iacute': 205,
                            'Icirc': 206,
                            'Igrave': 204,
                            'Iuml': 207,
                            'Ntilde': 209,
                            'Oacute': 211,
                            'Ocirc': 212,
                            'Ograve': 210,
                            'Oslash': 216,
                            'Otilde': 213,
                            'Ouml': 214,
                            'THORN': 222,
                            'Uacute': 218,
                            'Ucirc': 219,
                            'Ugrave': 217,
                            'Uuml': 220,
                            'Yacute': 221,
                            'aacute': 225,
                            'acirc': 226,
                            'aelig': 230,
                            'agrave': 224,
                            'aring': 229,
                            'atilde': 227,
                            'auml': 228,
                            'ccedil': 231,
                            'eacute': 233,
                            'ecirc': 234,
                            'egrave': 232,
                            'eth': 240,
                            'euml': 235,
                            'iacute': 237,
                            'icirc': 238,
                            'igrave': 236,
                            'iuml': 239,
                            'ntilde': 241,
                            'oacute': 243,
                            'ocirc': 244,
                            'ograve': 242,
                            'oslash': 248,
                            'otilde': 245,
                            'ouml': 246,
                            'szlig': 223,
                            'thorn': 254,
                            'uacute': 250,
                            'ucirc': 251,
                            'ugrave': 249,
                            'uuml': 252,
                            'yacute': 253,
                            'yuml': 255,
                            'copy': 169,
                            'reg': 174,
                            'nbsp': 160,
                            'iexcl': 161,
                            'cent': 162,
                            'pound': 163,
                            'curren': 164,
                            'yen': 165,
                            'brvbar': 166,
                            'sect': 167,
                            'uml': 168,
                            'ordf': 170,
                            'laquo': 171,
                            'not': 172,
                            'shy': 173,
                            'macr': 175,
                            'deg': 176,
                            'plusmn': 177,
                            'sup1': 185,
                            'sup2': 178,
                            'sup3': 179,
                            'acute': 180,
                            'micro': 181,
                            'para': 182,
                            'middot': 183,
                            'cedil': 184,
                            'ordm': 186,
                            'raquo': 187,
                            'frac14': 188,
                            'frac12': 189,
                            'frac34': 190,
                            'iquest': 191,
                            'times': 215,
                            'divide': 247,
                            'OElig': 338,
                            'oelig': 339,
                            'Scaron': 352,
                            'scaron': 353,
                            'Yuml': 376,
                            'fnof': 402,
                            'circ': 710,
                            'tilde': 732,
                            'Alpha': 913,
                            'Beta': 914,
                            'Gamma': 915,
                            'Delta': 916,
                            'Epsilon': 917,
                            'Zeta': 918,
                            'Eta': 919,
                            'Theta': 920,
                            'Iota': 921,
                            'Kappa': 922,
                            'Lambda': 923,
                            'Mu': 924,
                            'Nu': 925,
                            'Xi': 926,
                            'Omicron': 927,
                            'Pi': 928,
                            'Rho': 929,
                            'Sigma': 931,
                            'Tau': 932,
                            'Upsilon': 933,
                            'Phi': 934,
                            'Chi': 935,
                            'Psi': 936,
                            'Omega': 937,
                            'alpha': 945,
                            'beta': 946,
                            'gamma': 947,
                            'delta': 948,
                            'epsilon': 949,
                            'zeta': 950,
                            'eta': 951,
                            'theta': 952,
                            'iota': 953,
                            'kappa': 954,
                            'lambda': 955,
                            'mu': 956,
                            'nu': 957,
                            'xi': 958,
                            'omicron': 959,
                            'pi': 960,
                            'rho': 961,
                            'sigmaf': 962,
                            'sigma': 963,
                            'tau': 964,
                            'upsilon': 965,
                            'phi': 966,
                            'chi': 967,
                            'psi': 968,
                            'omega': 969,
                            'thetasym': 977,
                            'upsih': 978,
                            'piv': 982,
                            'ensp': 8194,
                            'emsp': 8195,
                            'thinsp': 8201,
                            'zwnj': 8204,
                            'zwj': 8205,
                            'lrm': 8206,
                            'rlm': 8207,
                            'ndash': 8211,
                            'mdash': 8212,
                            'lsquo': 8216,
                            'rsquo': 8217,
                            'sbquo': 8218,
                            'ldquo': 8220,
                            'rdquo': 8221,
                            'bdquo': 8222,
                            'dagger': 8224,
                            'Dagger': 8225,
                            'bull': 8226,
                            'hellip': 8230,
                            'permil': 8240,
                            'prime': 8242,
                            'Prime': 8243,
                            'lsaquo': 8249,
                            'rsaquo': 8250,
                            'oline': 8254,
                            'frasl': 8260,
                            'euro': 8364,
                            'image': 8465,
                            'weierp': 8472,
                            'real': 8476,
                            'trade': 8482,
                            'alefsym': 8501,
                            'larr': 8592,
                            'uarr': 8593,
                            'rarr': 8594,
                            'darr': 8595,
                            'harr': 8596,
                            'crarr': 8629,
                            'lArr': 8656,
                            'uArr': 8657,
                            'rArr': 8658,
                            'dArr': 8659,
                            'hArr': 8660,
                            'forall': 8704,
                            'part': 8706,
                            'exist': 8707,
                            'empty': 8709,
                            'nabla': 8711,
                            'isin': 8712,
                            'notin': 8713,
                            'ni': 8715,
                            'prod': 8719,
                            'sum': 8721,
                            'minus': 8722,
                            'lowast': 8727,
                            'radic': 8730,
                            'prop': 8733,
                            'infin': 8734,
                            'ang': 8736,
                            'and': 8743,
                            'or': 8744,
                            'cap': 8745,
                            'cup': 8746,
                            'int': 8747,
                            'there4': 8756,
                            'sim': 8764,
                            'cong': 8773,
                            'asymp': 8776,
                            'ne': 8800,
                            'equiv': 8801,
                            'le': 8804,
                            'ge': 8805,
                            'sub': 8834,
                            'sup': 8835,
                            'nsub': 8836,
                            'sube': 8838,
                            'supe': 8839,
                            'oplus': 8853,
                            'otimes': 8855,
                            'perp': 8869,
                            'sdot': 8901,
                            'lceil': 8968,
                            'rceil': 8969,
                            'lfloor': 8970,
                            'rfloor': 8971,
                            'lang': 9001,
                            'rang': 9002,
                            'loz': 9674,
                            'spades': 9824,
                            'clubs': 9827,
                            'hearts': 9829,
                            'diams': 9830
                        }

                        Object.keys(sax.ENTITIES).forEach(function (key) {
                            var e = sax.ENTITIES[key]
                            var s = typeof e === 'number' ? String.fromCharCode(e) : e
                            sax.ENTITIES[key] = s
                        })

                        for (var s in sax.STATE) {
                            sax.STATE[sax.STATE[s]] = s
                        }

                        // shorthand
                        S = sax.STATE

                        function emit(parser, event, data) {
                            parser[event] && parser[event](data)
                        }

                        function emitNode(parser, nodeType, data) {
                            if (parser.textNode) closeText(parser)
                            emit(parser, nodeType, data)
                        }

                        function closeText(parser) {
                            parser.textNode = textopts(parser.opt, parser.textNode)
                            if (parser.textNode) emit(parser, 'ontext', parser.textNode)
                            parser.textNode = ''
                        }

                        function textopts(opt, text) {
                            if (opt.trim) text = text.trim()
                            if (opt.normalize) text = text.replace(/\s+/g, ' ')
                            return text
                        }

                        function error(parser, er) {
                            closeText(parser)
                            if (parser.trackPosition) {
                                er += '\nLine: ' + parser.line +
                                    '\nColumn: ' + parser.column +
                                    '\nChar: ' + parser.c
                            }
                            er = new Error(er)
                            parser.error = er
                            emit(parser, 'onerror', er)
                            return parser
                        }

                        function end(parser) {
                            if (parser.sawRoot && !parser.closedRoot) strictFail(parser, 'Unclosed root tag')
                            if ((parser.state !== S.BEGIN) &&
                                (parser.state !== S.BEGIN_WHITESPACE) &&
                                (parser.state !== S.TEXT)) {
                                error(parser, 'Unexpected end')
                            }
                            closeText(parser)
                            parser.c = ''
                            parser.closed = true
                            emit(parser, 'onend')
                            SAXParser.call(parser, parser.strict, parser.opt)
                            return parser
                        }

                        function strictFail(parser, message) {
                            if (typeof parser !== 'object' || !(parser instanceof SAXParser)) {
                                throw new Error('bad call to strictFail')
                            }
                            if (parser.strict) {
                                error(parser, message)
                            }
                        }

                        function newTag(parser) {
                            if (!parser.strict) parser.tagName = parser.tagName[parser.looseCase]()
                            var parent = parser.tags[parser.tags.length - 1] || parser
                            var tag = parser.tag = { name: parser.tagName, attributes: {} }

                            // will be overridden if tag contails an xmlns="foo" or xmlns:foo="bar"
                            if (parser.opt.xmlns) {
                                tag.ns = parent.ns
                            }
                            parser.attribList.length = 0
                            emitNode(parser, 'onopentagstart', tag)
                        }

                        function qname(name, attribute) {
                            var i = name.indexOf(':')
                            var qualName = i < 0 ? ['', name] : name.split(':')
                            var prefix = qualName[0]
                            var local = qualName[1]

                            // <x "xmlns"="http://foo">
                            if (attribute && name === 'xmlns') {
                                prefix = 'xmlns'
                                local = ''
                            }

                            return { prefix: prefix, local: local }
                        }

                        function attrib(parser) {
                            if (!parser.strict) {
                                parser.attribName = parser.attribName[parser.looseCase]()
                            }

                            if (parser.attribList.indexOf(parser.attribName) !== -1 ||
                                parser.tag.attributes.hasOwnProperty(parser.attribName)) {
                                parser.attribName = parser.attribValue = ''
                                return
                            }

                            if (parser.opt.xmlns) {
                                var qn = qname(parser.attribName, true)
                                var prefix = qn.prefix
                                var local = qn.local

                                if (prefix === 'xmlns') {
                                    // namespace binding attribute. push the binding into scope
                                    if (local === 'xml' && parser.attribValue !== XML_NAMESPACE) {
                                        strictFail(parser,
                                            'xml: prefix must be bound to ' + XML_NAMESPACE + '\n' +
                                            'Actual: ' + parser.attribValue)
                                    } else if (local === 'xmlns' && parser.attribValue !== XMLNS_NAMESPACE) {
                                        strictFail(parser,
                                            'xmlns: prefix must be bound to ' + XMLNS_NAMESPACE + '\n' +
                                            'Actual: ' + parser.attribValue)
                                    } else {
                                        var tag = parser.tag
                                        var parent = parser.tags[parser.tags.length - 1] || parser
                                        if (tag.ns === parent.ns) {
                                            tag.ns = Object.create(parent.ns)
                                        }
                                        tag.ns[local] = parser.attribValue
                                    }
                                }

                                // defer onattribute events until all attributes have been seen
                                // so any new bindings can take effect. preserve attribute order
                                // so deferred events can be emitted in document order
                                parser.attribList.push([parser.attribName, parser.attribValue])
                            } else {
                                // in non-xmlns mode, we can emit the event right away
                                parser.tag.attributes[parser.attribName] = parser.attribValue
                                emitNode(parser, 'onattribute', {
                                    name: parser.attribName,
                                    value: parser.attribValue
                                })
                            }

                            parser.attribName = parser.attribValue = ''
                        }

                        function openTag(parser, selfClosing) {
                            if (parser.opt.xmlns) {
                                // emit namespace binding events
                                var tag = parser.tag

                                // add namespace info to tag
                                var qn = qname(parser.tagName)
                                tag.prefix = qn.prefix
                                tag.local = qn.local
                                tag.uri = tag.ns[qn.prefix] || ''

                                if (tag.prefix && !tag.uri) {
                                    strictFail(parser, 'Unbound namespace prefix: ' +
                                        JSON.stringify(parser.tagName))
                                    tag.uri = qn.prefix
                                }

                                var parent = parser.tags[parser.tags.length - 1] || parser
                                if (tag.ns && parent.ns !== tag.ns) {
                                    Object.keys(tag.ns).forEach(function (p) {
                                        emitNode(parser, 'onopennamespace', {
                                            prefix: p,
                                            uri: tag.ns[p]
                                        })
                                    })
                                }

                                // handle deferred onattribute events
                                // Note: do not apply default ns to attributes:
                                //   http://www.w3.org/TR/REC-xml-names/#defaulting
                                for (var i = 0, l = parser.attribList.length; i < l; i++) {
                                    var nv = parser.attribList[i]
                                    var name = nv[0]
                                    var value = nv[1]
                                    var qualName = qname(name, true)
                                    var prefix = qualName.prefix
                                    var local = qualName.local
                                    var uri = prefix === '' ? '' : (tag.ns[prefix] || '')
                                    var a = {
                                        name: name,
                                        value: value,
                                        prefix: prefix,
                                        local: local,
                                        uri: uri
                                    }

                                    // if there's any attributes with an undefined namespace,
                                    // then fail on them now.
                                    if (prefix && prefix !== 'xmlns' && !uri) {
                                        strictFail(parser, 'Unbound namespace prefix: ' +
                                            JSON.stringify(prefix))
                                        a.uri = prefix
                                    }
                                    parser.tag.attributes[name] = a
                                    emitNode(parser, 'onattribute', a)
                                }
                                parser.attribList.length = 0
                            }

                            parser.tag.isSelfClosing = !!selfClosing

                            // process the tag
                            parser.sawRoot = true
                            parser.tags.push(parser.tag)
                            emitNode(parser, 'onopentag', parser.tag)
                            if (!selfClosing) {
                                // special case for <script> in non-strict mode.
                                if (!parser.noscript && parser.tagName.toLowerCase() === 'script') {
                                    parser.state = S.SCRIPT
                                } else {
                                    parser.state = S.TEXT
                                }
                                parser.tag = null
                                parser.tagName = ''
                            }
                            parser.attribName = parser.attribValue = ''
                            parser.attribList.length = 0
                        }

                        function closeTag(parser) {
                            if (!parser.tagName) {
                                strictFail(parser, 'Weird empty close tag.')
                                parser.textNode += '</>'
                                parser.state = S.TEXT
                                return
                            }

                            if (parser.script) {
                                if (parser.tagName !== 'script') {
                                    parser.script += '</' + parser.tagName + '>'
                                    parser.tagName = ''
                                    parser.state = S.SCRIPT
                                    return
                                }
                                emitNode(parser, 'onscript', parser.script)
                                parser.script = ''
                            }

                            // first make sure that the closing tag actually exists.
                            // <a><b></c></b></a> will close everything, otherwise.
                            var t = parser.tags.length
                            var tagName = parser.tagName
                            if (!parser.strict) {
                                tagName = tagName[parser.looseCase]()
                            }
                            var closeTo = tagName
                            while (t--) {
                                var close = parser.tags[t]
                                if (close.name !== closeTo) {
                                    // fail the first time in strict mode
                                    strictFail(parser, 'Unexpected close tag')
                                } else {
                                    break
                                }
                            }

                            // didn't find it.  we already failed for strict, so just abort.
                            if (t < 0) {
                                strictFail(parser, 'Unmatched closing tag: ' + parser.tagName)
                                parser.textNode += '</' + parser.tagName + '>'
                                parser.state = S.TEXT
                                return
                            }
                            parser.tagName = tagName
                            var s = parser.tags.length
                            while (s-- > t) {
                                var tag = parser.tag = parser.tags.pop()
                                parser.tagName = parser.tag.name
                                emitNode(parser, 'onclosetag', parser.tagName)

                                var x = {}
                                for (var i in tag.ns) {
                                    x[i] = tag.ns[i]
                                }

                                var parent = parser.tags[parser.tags.length - 1] || parser
                                if (parser.opt.xmlns && tag.ns !== parent.ns) {
                                    // remove namespace bindings introduced by tag
                                    Object.keys(tag.ns).forEach(function (p) {
                                        var n = tag.ns[p]
                                        emitNode(parser, 'onclosenamespace', { prefix: p, uri: n })
                                    })
                                }
                            }
                            if (t === 0) parser.closedRoot = true
                            parser.tagName = parser.attribValue = parser.attribName = ''
                            parser.attribList.length = 0
                            parser.state = S.TEXT
                        }

                        function parseEntity(parser) {
                            var entity = parser.entity
                            var entityLC = entity.toLowerCase()
                            var num
                            var numStr = ''

                            if (parser.ENTITIES[entity]) {
                                return parser.ENTITIES[entity]
                            }
                            if (parser.ENTITIES[entityLC]) {
                                return parser.ENTITIES[entityLC]
                            }
                            entity = entityLC
                            if (entity.charAt(0) === '#') {
                                if (entity.charAt(1) === 'x') {
                                    entity = entity.slice(2)
                                    num = parseInt(entity, 16)
                                    numStr = num.toString(16)
                                } else {
                                    entity = entity.slice(1)
                                    num = parseInt(entity, 10)
                                    numStr = num.toString(10)
                                }
                            }
                            entity = entity.replace(/^0+/, '')
                            if (isNaN(num) || numStr.toLowerCase() !== entity) {
                                strictFail(parser, 'Invalid character entity')
                                return '&' + parser.entity + ';'
                            }

                            return String.fromCodePoint(num)
                        }

                        function beginWhiteSpace(parser, c) {
                            if (c === '<') {
                                parser.state = S.OPEN_WAKA
                                parser.startTagPosition = parser.position
                            } else if (!isWhitespace(c)) {
                                // have to process this as a text node.
                                // weird, but happens.
                                strictFail(parser, 'Non-whitespace before first tag.')
                                parser.textNode = c
                                parser.state = S.TEXT
                            }
                        }

                        function charAt(chunk, i) {
                            var result = ''
                            if (i < chunk.length) {
                                result = chunk.charAt(i)
                            }
                            return result
                        }

                        function write(chunk) {
                            var parser = this
                            if (this.error) {
                                throw this.error
                            }
                            if (parser.closed) {
                                return error(parser,
                                    'Cannot write after close. Assign an onready handler.')
                            }
                            if (chunk === null) {
                                return end(parser)
                            }
                            if (typeof chunk === 'object') {
                                chunk = chunk.toString()
                            }
                            var i = 0
                            var c = ''
                            while (true) {
                                c = charAt(chunk, i++)
                                parser.c = c

                                if (!c) {
                                    break
                                }

                                if (parser.trackPosition) {
                                    parser.position++
                                    if (c === '\n') {
                                        parser.line++
                                        parser.column = 0
                                    } else {
                                        parser.column++
                                    }
                                }

                                switch (parser.state) {
                                    case S.BEGIN:
                                        parser.state = S.BEGIN_WHITESPACE
                                        if (c === '\uFEFF') {
                                            continue
                                        }
                                        beginWhiteSpace(parser, c)
                                        continue

                                    case S.BEGIN_WHITESPACE:
                                        beginWhiteSpace(parser, c)
                                        continue

                                    case S.TEXT:
                                        if (parser.sawRoot && !parser.closedRoot) {
                                            var starti = i - 1
                                            while (c && c !== '<' && c !== '&') {
                                                c = charAt(chunk, i++)
                                                if (c && parser.trackPosition) {
                                                    parser.position++
                                                    if (c === '\n') {
                                                        parser.line++
                                                        parser.column = 0
                                                    } else {
                                                        parser.column++
                                                    }
                                                }
                                            }
                                            parser.textNode += chunk.substring(starti, i - 1)
                                        }
                                        if (c === '<' && !(parser.sawRoot && parser.closedRoot && !parser.strict)) {
                                            parser.state = S.OPEN_WAKA
                                            parser.startTagPosition = parser.position
                                        } else {
                                            if (!isWhitespace(c) && (!parser.sawRoot || parser.closedRoot)) {
                                                strictFail(parser, 'Text data outside of root node.')
                                            }
                                            if (c === '&') {
                                                parser.state = S.TEXT_ENTITY
                                            } else {
                                                parser.textNode += c
                                            }
                                        }
                                        continue

                                    case S.SCRIPT:
                                        // only non-strict
                                        if (c === '<') {
                                            parser.state = S.SCRIPT_ENDING
                                        } else {
                                            parser.script += c
                                        }
                                        continue

                                    case S.SCRIPT_ENDING:
                                        if (c === '/') {
                                            parser.state = S.CLOSE_TAG
                                        } else {
                                            parser.script += '<' + c
                                            parser.state = S.SCRIPT
                                        }
                                        continue

                                    case S.OPEN_WAKA:
                                        // either a /, ?, !, or text is coming next.
                                        if (c === '!') {
                                            parser.state = S.SGML_DECL
                                            parser.sgmlDecl = ''
                                        } else if (isWhitespace(c)) {
                                            // wait for it...
                                        } else if (isMatch(nameStart, c)) {
                                            parser.state = S.OPEN_TAG
                                            parser.tagName = c
                                        } else if (c === '/') {
                                            parser.state = S.CLOSE_TAG
                                            parser.tagName = ''
                                        } else if (c === '?') {
                                            parser.state = S.PROC_INST
                                            parser.procInstName = parser.procInstBody = ''
                                        } else {
                                            strictFail(parser, 'Unencoded <')
                                            // if there was some whitespace, then add that in.
                                            if (parser.startTagPosition + 1 < parser.position) {
                                                var pad = parser.position - parser.startTagPosition
                                                c = new Array(pad).join(' ') + c
                                            }
                                            parser.textNode += '<' + c
                                            parser.state = S.TEXT
                                        }
                                        continue

                                    case S.SGML_DECL:
                                        if ((parser.sgmlDecl + c).toUpperCase() === CDATA) {
                                            emitNode(parser, 'onopencdata')
                                            parser.state = S.CDATA
                                            parser.sgmlDecl = ''
                                            parser.cdata = ''
                                        } else if (parser.sgmlDecl + c === '--') {
                                            parser.state = S.COMMENT
                                            parser.comment = ''
                                            parser.sgmlDecl = ''
                                        } else if ((parser.sgmlDecl + c).toUpperCase() === DOCTYPE) {
                                            parser.state = S.DOCTYPE
                                            if (parser.doctype || parser.sawRoot) {
                                                strictFail(parser,
                                                    'Inappropriately located doctype declaration')
                                            }
                                            parser.doctype = ''
                                            parser.sgmlDecl = ''
                                        } else if (c === '>') {
                                            emitNode(parser, 'onsgmldeclaration', parser.sgmlDecl)
                                            parser.sgmlDecl = ''
                                            parser.state = S.TEXT
                                        } else if (isQuote(c)) {
                                            parser.state = S.SGML_DECL_QUOTED
                                            parser.sgmlDecl += c
                                        } else {
                                            parser.sgmlDecl += c
                                        }
                                        continue

                                    case S.SGML_DECL_QUOTED:
                                        if (c === parser.q) {
                                            parser.state = S.SGML_DECL
                                            parser.q = ''
                                        }
                                        parser.sgmlDecl += c
                                        continue

                                    case S.DOCTYPE:
                                        if (c === '>') {
                                            parser.state = S.TEXT
                                            emitNode(parser, 'ondoctype', parser.doctype)
                                            parser.doctype = true // just remember that we saw it.
                                        } else {
                                            parser.doctype += c
                                            if (c === '[') {
                                                parser.state = S.DOCTYPE_DTD
                                            } else if (isQuote(c)) {
                                                parser.state = S.DOCTYPE_QUOTED
                                                parser.q = c
                                            }
                                        }
                                        continue

                                    case S.DOCTYPE_QUOTED:
                                        parser.doctype += c
                                        if (c === parser.q) {
                                            parser.q = ''
                                            parser.state = S.DOCTYPE
                                        }
                                        continue

                                    case S.DOCTYPE_DTD:
                                        parser.doctype += c
                                        if (c === ']') {
                                            parser.state = S.DOCTYPE
                                        } else if (isQuote(c)) {
                                            parser.state = S.DOCTYPE_DTD_QUOTED
                                            parser.q = c
                                        }
                                        continue

                                    case S.DOCTYPE_DTD_QUOTED:
                                        parser.doctype += c
                                        if (c === parser.q) {
                                            parser.state = S.DOCTYPE_DTD
                                            parser.q = ''
                                        }
                                        continue

                                    case S.COMMENT:
                                        if (c === '-') {
                                            parser.state = S.COMMENT_ENDING
                                        } else {
                                            parser.comment += c
                                        }
                                        continue

                                    case S.COMMENT_ENDING:
                                        if (c === '-') {
                                            parser.state = S.COMMENT_ENDED
                                            parser.comment = textopts(parser.opt, parser.comment)
                                            if (parser.comment) {
                                                emitNode(parser, 'oncomment', parser.comment)
                                            }
                                            parser.comment = ''
                                        } else {
                                            parser.comment += '-' + c
                                            parser.state = S.COMMENT
                                        }
                                        continue

                                    case S.COMMENT_ENDED:
                                        if (c !== '>') {
                                            strictFail(parser, 'Malformed comment')
                                            // allow <!-- blah -- bloo --> in non-strict mode,
                                            // which is a comment of " blah -- bloo "
                                            parser.comment += '--' + c
                                            parser.state = S.COMMENT
                                        } else {
                                            parser.state = S.TEXT
                                        }
                                        continue

                                    case S.CDATA:
                                        if (c === ']') {
                                            parser.state = S.CDATA_ENDING
                                        } else {
                                            parser.cdata += c
                                        }
                                        continue

                                    case S.CDATA_ENDING:
                                        if (c === ']') {
                                            parser.state = S.CDATA_ENDING_2
                                        } else {
                                            parser.cdata += ']' + c
                                            parser.state = S.CDATA
                                        }
                                        continue

                                    case S.CDATA_ENDING_2:
                                        if (c === '>') {
                                            if (parser.cdata) {
                                                emitNode(parser, 'oncdata', parser.cdata)
                                            }
                                            emitNode(parser, 'onclosecdata')
                                            parser.cdata = ''
                                            parser.state = S.TEXT
                                        } else if (c === ']') {
                                            parser.cdata += ']'
                                        } else {
                                            parser.cdata += ']]' + c
                                            parser.state = S.CDATA
                                        }
                                        continue

                                    case S.PROC_INST:
                                        if (c === '?') {
                                            parser.state = S.PROC_INST_ENDING
                                        } else if (isWhitespace(c)) {
                                            parser.state = S.PROC_INST_BODY
                                        } else {
                                            parser.procInstName += c
                                        }
                                        continue

                                    case S.PROC_INST_BODY:
                                        if (!parser.procInstBody && isWhitespace(c)) {
                                            continue
                                        } else if (c === '?') {
                                            parser.state = S.PROC_INST_ENDING
                                        } else {
                                            parser.procInstBody += c
                                        }
                                        continue

                                    case S.PROC_INST_ENDING:
                                        if (c === '>') {
                                            emitNode(parser, 'onprocessinginstruction', {
                                                name: parser.procInstName,
                                                body: parser.procInstBody
                                            })
                                            parser.procInstName = parser.procInstBody = ''
                                            parser.state = S.TEXT
                                        } else {
                                            parser.procInstBody += '?' + c
                                            parser.state = S.PROC_INST_BODY
                                        }
                                        continue

                                    case S.OPEN_TAG:
                                        if (isMatch(nameBody, c)) {
                                            parser.tagName += c
                                        } else {
                                            newTag(parser)
                                            if (c === '>') {
                                                openTag(parser)
                                            } else if (c === '/') {
                                                parser.state = S.OPEN_TAG_SLASH
                                            } else {
                                                if (!isWhitespace(c)) {
                                                    strictFail(parser, 'Invalid character in tag name')
                                                }
                                                parser.state = S.ATTRIB
                                            }
                                        }
                                        continue

                                    case S.OPEN_TAG_SLASH:
                                        if (c === '>') {
                                            openTag(parser, true)
                                            closeTag(parser)
                                        } else {
                                            strictFail(parser, 'Forward-slash in opening tag not followed by >')
                                            parser.state = S.ATTRIB
                                        }
                                        continue

                                    case S.ATTRIB:
                                        // haven't read the attribute name yet.
                                        if (isWhitespace(c)) {
                                            continue
                                        } else if (c === '>') {
                                            openTag(parser)
                                        } else if (c === '/') {
                                            parser.state = S.OPEN_TAG_SLASH
                                        } else if (isMatch(nameStart, c)) {
                                            parser.attribName = c
                                            parser.attribValue = ''
                                            parser.state = S.ATTRIB_NAME
                                        } else {
                                            strictFail(parser, 'Invalid attribute name')
                                        }
                                        continue

                                    case S.ATTRIB_NAME:
                                        if (c === '=') {
                                            parser.state = S.ATTRIB_VALUE
                                        } else if (c === '>') {
                                            strictFail(parser, 'Attribute without value')
                                            parser.attribValue = parser.attribName
                                            attrib(parser)
                                            openTag(parser)
                                        } else if (isWhitespace(c)) {
                                            parser.state = S.ATTRIB_NAME_SAW_WHITE
                                        } else if (isMatch(nameBody, c)) {
                                            parser.attribName += c
                                        } else {
                                            strictFail(parser, 'Invalid attribute name')
                                        }
                                        continue

                                    case S.ATTRIB_NAME_SAW_WHITE:
                                        if (c === '=') {
                                            parser.state = S.ATTRIB_VALUE
                                        } else if (isWhitespace(c)) {
                                            continue
                                        } else {
                                            strictFail(parser, 'Attribute without value')
                                            parser.tag.attributes[parser.attribName] = ''
                                            parser.attribValue = ''
                                            emitNode(parser, 'onattribute', {
                                                name: parser.attribName,
                                                value: ''
                                            })
                                            parser.attribName = ''
                                            if (c === '>') {
                                                openTag(parser)
                                            } else if (isMatch(nameStart, c)) {
                                                parser.attribName = c
                                                parser.state = S.ATTRIB_NAME
                                            } else {
                                                strictFail(parser, 'Invalid attribute name')
                                                parser.state = S.ATTRIB
                                            }
                                        }
                                        continue

                                    case S.ATTRIB_VALUE:
                                        if (isWhitespace(c)) {
                                            continue
                                        } else if (isQuote(c)) {
                                            parser.q = c
                                            parser.state = S.ATTRIB_VALUE_QUOTED
                                        } else {
                                            strictFail(parser, 'Unquoted attribute value')
                                            parser.state = S.ATTRIB_VALUE_UNQUOTED
                                            parser.attribValue = c
                                        }
                                        continue

                                    case S.ATTRIB_VALUE_QUOTED:
                                        if (c !== parser.q) {
                                            if (c === '&') {
                                                parser.state = S.ATTRIB_VALUE_ENTITY_Q
                                            } else {
                                                parser.attribValue += c
                                            }
                                            continue
                                        }
                                        attrib(parser)
                                        parser.q = ''
                                        parser.state = S.ATTRIB_VALUE_CLOSED
                                        continue

                                    case S.ATTRIB_VALUE_CLOSED:
                                        if (isWhitespace(c)) {
                                            parser.state = S.ATTRIB
                                        } else if (c === '>') {
                                            openTag(parser)
                                        } else if (c === '/') {
                                            parser.state = S.OPEN_TAG_SLASH
                                        } else if (isMatch(nameStart, c)) {
                                            strictFail(parser, 'No whitespace between attributes')
                                            parser.attribName = c
                                            parser.attribValue = ''
                                            parser.state = S.ATTRIB_NAME
                                        } else {
                                            strictFail(parser, 'Invalid attribute name')
                                        }
                                        continue

                                    case S.ATTRIB_VALUE_UNQUOTED:
                                        if (!isAttribEnd(c)) {
                                            if (c === '&') {
                                                parser.state = S.ATTRIB_VALUE_ENTITY_U
                                            } else {
                                                parser.attribValue += c
                                            }
                                            continue
                                        }
                                        attrib(parser)
                                        if (c === '>') {
                                            openTag(parser)
                                        } else {
                                            parser.state = S.ATTRIB
                                        }
                                        continue

                                    case S.CLOSE_TAG:
                                        if (!parser.tagName) {
                                            if (isWhitespace(c)) {
                                                continue
                                            } else if (notMatch(nameStart, c)) {
                                                if (parser.script) {
                                                    parser.script += '</' + c
                                                    parser.state = S.SCRIPT
                                                } else {
                                                    strictFail(parser, 'Invalid tagname in closing tag.')
                                                }
                                            } else {
                                                parser.tagName = c
                                            }
                                        } else if (c === '>') {
                                            closeTag(parser)
                                        } else if (isMatch(nameBody, c)) {
                                            parser.tagName += c
                                        } else if (parser.script) {
                                            parser.script += '</' + parser.tagName
                                            parser.tagName = ''
                                            parser.state = S.SCRIPT
                                        } else {
                                            if (!isWhitespace(c)) {
                                                strictFail(parser, 'Invalid tagname in closing tag')
                                            }
                                            parser.state = S.CLOSE_TAG_SAW_WHITE
                                        }
                                        continue

                                    case S.CLOSE_TAG_SAW_WHITE:
                                        if (isWhitespace(c)) {
                                            continue
                                        }
                                        if (c === '>') {
                                            closeTag(parser)
                                        } else {
                                            strictFail(parser, 'Invalid characters in closing tag')
                                        }
                                        continue

                                    case S.TEXT_ENTITY:
                                    case S.ATTRIB_VALUE_ENTITY_Q:
                                    case S.ATTRIB_VALUE_ENTITY_U:
                                        var returnState
                                        var buffer
                                        switch (parser.state) {
                                            case S.TEXT_ENTITY:
                                                returnState = S.TEXT
                                                buffer = 'textNode'
                                                break

                                            case S.ATTRIB_VALUE_ENTITY_Q:
                                                returnState = S.ATTRIB_VALUE_QUOTED
                                                buffer = 'attribValue'
                                                break

                                            case S.ATTRIB_VALUE_ENTITY_U:
                                                returnState = S.ATTRIB_VALUE_UNQUOTED
                                                buffer = 'attribValue'
                                                break
                                        }

                                        if (c === ';') {
                                            parser[buffer] += parseEntity(parser)
                                            parser.entity = ''
                                            parser.state = returnState
                                        } else if (isMatch(parser.entity.length ? entityBody : entityStart, c)) {
                                            parser.entity += c
                                        } else {
                                            strictFail(parser, 'Invalid character in entity name')
                                            parser[buffer] += '&' + parser.entity + c
                                            parser.entity = ''
                                            parser.state = returnState
                                        }

                                        continue

                                    default:
                                        throw new Error(parser, 'Unknown state: ' + parser.state)
                                }
                            } // while

                            if (parser.position >= parser.bufferCheckPosition) {
                                checkBufferLength(parser)
                            }
                            return parser
                        }

                        /*! http://mths.be/fromcodepoint v0.1.0 by @mathias */
                        /* istanbul ignore next */
                        if (!String.fromCodePoint) {
                            (function () {
                                var stringFromCharCode = String.fromCharCode
                                var floor = Math.floor
                                var fromCodePoint = function () {
                                    var MAX_SIZE = 0x4000
                                    var codeUnits = []
                                    var highSurrogate
                                    var lowSurrogate
                                    var index = -1
                                    var length = arguments.length
                                    if (!length) {
                                        return ''
                                    }
                                    var result = ''
                                    while (++index < length) {
                                        var codePoint = Number(arguments[index])
                                        if (
                                            !isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
                                            codePoint < 0 || // not a valid Unicode code point
                                            codePoint > 0x10FFFF || // not a valid Unicode code point
                                            floor(codePoint) !== codePoint // not an integer
                                        ) {
                                            throw RangeError('Invalid code point: ' + codePoint)
                                        }
                                        if (codePoint <= 0xFFFF) { // BMP code point
                                            codeUnits.push(codePoint)
                                        } else { // Astral code point; split in surrogate halves
                                            // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
                                            codePoint -= 0x10000
                                            highSurrogate = (codePoint >> 10) + 0xD800
                                            lowSurrogate = (codePoint % 0x400) + 0xDC00
                                            codeUnits.push(highSurrogate, lowSurrogate)
                                        }
                                        if (index + 1 === length || codeUnits.length > MAX_SIZE) {
                                            result += stringFromCharCode.apply(null, codeUnits)
                                            codeUnits.length = 0
                                        }
                                    }
                                    return result
                                }
                                /* istanbul ignore next */
                                if (Object.defineProperty) {
                                    Object.defineProperty(String, 'fromCodePoint', {
                                        value: fromCodePoint,
                                        configurable: true,
                                        writable: true
                                    })
                                } else {
                                    String.fromCodePoint = fromCodePoint
                                }
                            }())
                        }
                    })(typeof exports === 'undefined' ? this.sax = {} : exports)

                }).call(this)
            }).call(this, require("buffer").Buffer)
        }, { "buffer": 3, "stream": 9, "string_decoder": 24 }], 111: [function (require, module, exports) {
            /** @license URI.js v4.4.1 (c) 2011 Gary Court. License: http://github.com/garycourt/uri-js */
            (function (global, factory) {
                typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
                    typeof define === 'function' && define.amd ? define(['exports'], factory) :
                        (factory((global.URI = global.URI || {})));
            }(this, (function (exports) {
                'use strict';

                function merge() {
                    for (var _len = arguments.length, sets = Array(_len), _key = 0; _key < _len; _key++) {
                        sets[_key] = arguments[_key];
                    }

                    if (sets.length > 1) {
                        sets[0] = sets[0].slice(0, -1);
                        var xl = sets.length - 1;
                        for (var x = 1; x < xl; ++x) {
                            sets[x] = sets[x].slice(1, -1);
                        }
                        sets[xl] = sets[xl].slice(1);
                        return sets.join('');
                    } else {
                        return sets[0];
                    }
                }
                function subexp(str) {
                    return "(?:" + str + ")";
                }
                function typeOf(o) {
                    return o === undefined ? "undefined" : o === null ? "null" : Object.prototype.toString.call(o).split(" ").pop().split("]").shift().toLowerCase();
                }
                function toUpperCase(str) {
                    return str.toUpperCase();
                }
                function toArray(obj) {
                    return obj !== undefined && obj !== null ? obj instanceof Array ? obj : typeof obj.length !== "number" || obj.split || obj.setInterval || obj.call ? [obj] : Array.prototype.slice.call(obj) : [];
                }
                function assign(target, source) {
                    var obj = target;
                    if (source) {
                        for (var key in source) {
                            obj[key] = source[key];
                        }
                    }
                    return obj;
                }

                function buildExps(isIRI) {
                    var ALPHA$$ = "[A-Za-z]",
                        CR$ = "[\\x0D]",
                        DIGIT$$ = "[0-9]",
                        DQUOTE$$ = "[\\x22]",
                        HEXDIG$$ = merge(DIGIT$$, "[A-Fa-f]"),
                        //case-insensitive
                        LF$$ = "[\\x0A]",
                        SP$$ = "[\\x20]",
                        PCT_ENCODED$ = subexp(subexp("%[EFef]" + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$) + "|" + subexp("%[89A-Fa-f]" + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$) + "|" + subexp("%" + HEXDIG$$ + HEXDIG$$)),
                        //expanded
                        GEN_DELIMS$$ = "[\\:\\/\\?\\#\\[\\]\\@]",
                        SUB_DELIMS$$ = "[\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=]",
                        RESERVED$$ = merge(GEN_DELIMS$$, SUB_DELIMS$$),
                        UCSCHAR$$ = isIRI ? "[\\xA0-\\u200D\\u2010-\\u2029\\u202F-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]" : "[]",
                        //subset, excludes bidi control characters
                        IPRIVATE$$ = isIRI ? "[\\uE000-\\uF8FF]" : "[]",
                        //subset
                        UNRESERVED$$ = merge(ALPHA$$, DIGIT$$, "[\\-\\.\\_\\~]", UCSCHAR$$),
                        SCHEME$ = subexp(ALPHA$$ + merge(ALPHA$$, DIGIT$$, "[\\+\\-\\.]") + "*"),
                        USERINFO$ = subexp(subexp(PCT_ENCODED$ + "|" + merge(UNRESERVED$$, SUB_DELIMS$$, "[\\:]")) + "*"),
                        DEC_OCTET$ = subexp(subexp("25[0-5]") + "|" + subexp("2[0-4]" + DIGIT$$) + "|" + subexp("1" + DIGIT$$ + DIGIT$$) + "|" + subexp("[1-9]" + DIGIT$$) + "|" + DIGIT$$),
                        DEC_OCTET_RELAXED$ = subexp(subexp("25[0-5]") + "|" + subexp("2[0-4]" + DIGIT$$) + "|" + subexp("1" + DIGIT$$ + DIGIT$$) + "|" + subexp("0?[1-9]" + DIGIT$$) + "|0?0?" + DIGIT$$),
                        //relaxed parsing rules
                        IPV4ADDRESS$ = subexp(DEC_OCTET_RELAXED$ + "\\." + DEC_OCTET_RELAXED$ + "\\." + DEC_OCTET_RELAXED$ + "\\." + DEC_OCTET_RELAXED$),
                        H16$ = subexp(HEXDIG$$ + "{1,4}"),
                        LS32$ = subexp(subexp(H16$ + "\\:" + H16$) + "|" + IPV4ADDRESS$),
                        IPV6ADDRESS1$ = subexp(subexp(H16$ + "\\:") + "{6}" + LS32$),
                        //                           6( h16 ":" ) ls32
                        IPV6ADDRESS2$ = subexp("\\:\\:" + subexp(H16$ + "\\:") + "{5}" + LS32$),
                        //                      "::" 5( h16 ":" ) ls32
                        IPV6ADDRESS3$ = subexp(subexp(H16$) + "?\\:\\:" + subexp(H16$ + "\\:") + "{4}" + LS32$),
                        //[               h16 ] "::" 4( h16 ":" ) ls32
                        IPV6ADDRESS4$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,1}" + H16$) + "?\\:\\:" + subexp(H16$ + "\\:") + "{3}" + LS32$),
                        //[ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
                        IPV6ADDRESS5$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,2}" + H16$) + "?\\:\\:" + subexp(H16$ + "\\:") + "{2}" + LS32$),
                        //[ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
                        IPV6ADDRESS6$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,3}" + H16$) + "?\\:\\:" + H16$ + "\\:" + LS32$),
                        //[ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
                        IPV6ADDRESS7$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,4}" + H16$) + "?\\:\\:" + LS32$),
                        //[ *4( h16 ":" ) h16 ] "::"              ls32
                        IPV6ADDRESS8$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,5}" + H16$) + "?\\:\\:" + H16$),
                        //[ *5( h16 ":" ) h16 ] "::"              h16
                        IPV6ADDRESS9$ = subexp(subexp(subexp(H16$ + "\\:") + "{0,6}" + H16$) + "?\\:\\:"),
                        //[ *6( h16 ":" ) h16 ] "::"
                        IPV6ADDRESS$ = subexp([IPV6ADDRESS1$, IPV6ADDRESS2$, IPV6ADDRESS3$, IPV6ADDRESS4$, IPV6ADDRESS5$, IPV6ADDRESS6$, IPV6ADDRESS7$, IPV6ADDRESS8$, IPV6ADDRESS9$].join("|")),
                        ZONEID$ = subexp(subexp(UNRESERVED$$ + "|" + PCT_ENCODED$) + "+"),
                        //RFC 6874
                        IPV6ADDRZ$ = subexp(IPV6ADDRESS$ + "\\%25" + ZONEID$),
                        //RFC 6874
                        IPV6ADDRZ_RELAXED$ = subexp(IPV6ADDRESS$ + subexp("\\%25|\\%(?!" + HEXDIG$$ + "{2})") + ZONEID$),
                        //RFC 6874, with relaxed parsing rules
                        IPVFUTURE$ = subexp("[vV]" + HEXDIG$$ + "+\\." + merge(UNRESERVED$$, SUB_DELIMS$$, "[\\:]") + "+"),
                        IP_LITERAL$ = subexp("\\[" + subexp(IPV6ADDRZ_RELAXED$ + "|" + IPV6ADDRESS$ + "|" + IPVFUTURE$) + "\\]"),
                        //RFC 6874
                        REG_NAME$ = subexp(subexp(PCT_ENCODED$ + "|" + merge(UNRESERVED$$, SUB_DELIMS$$)) + "*"),
                        HOST$ = subexp(IP_LITERAL$ + "|" + IPV4ADDRESS$ + "(?!" + REG_NAME$ + ")" + "|" + REG_NAME$),
                        PORT$ = subexp(DIGIT$$ + "*"),
                        AUTHORITY$ = subexp(subexp(USERINFO$ + "@") + "?" + HOST$ + subexp("\\:" + PORT$) + "?"),
                        PCHAR$ = subexp(PCT_ENCODED$ + "|" + merge(UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@]")),
                        SEGMENT$ = subexp(PCHAR$ + "*"),
                        SEGMENT_NZ$ = subexp(PCHAR$ + "+"),
                        SEGMENT_NZ_NC$ = subexp(subexp(PCT_ENCODED$ + "|" + merge(UNRESERVED$$, SUB_DELIMS$$, "[\\@]")) + "+"),
                        PATH_ABEMPTY$ = subexp(subexp("\\/" + SEGMENT$) + "*"),
                        PATH_ABSOLUTE$ = subexp("\\/" + subexp(SEGMENT_NZ$ + PATH_ABEMPTY$) + "?"),
                        //simplified
                        PATH_NOSCHEME$ = subexp(SEGMENT_NZ_NC$ + PATH_ABEMPTY$),
                        //simplified
                        PATH_ROOTLESS$ = subexp(SEGMENT_NZ$ + PATH_ABEMPTY$),
                        //simplified
                        PATH_EMPTY$ = "(?!" + PCHAR$ + ")",
                        PATH$ = subexp(PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$),
                        QUERY$ = subexp(subexp(PCHAR$ + "|" + merge("[\\/\\?]", IPRIVATE$$)) + "*"),
                        FRAGMENT$ = subexp(subexp(PCHAR$ + "|[\\/\\?]") + "*"),
                        HIER_PART$ = subexp(subexp("\\/\\/" + AUTHORITY$ + PATH_ABEMPTY$) + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$),
                        URI$ = subexp(SCHEME$ + "\\:" + HIER_PART$ + subexp("\\?" + QUERY$) + "?" + subexp("\\#" + FRAGMENT$) + "?"),
                        RELATIVE_PART$ = subexp(subexp("\\/\\/" + AUTHORITY$ + PATH_ABEMPTY$) + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_EMPTY$),
                        RELATIVE$ = subexp(RELATIVE_PART$ + subexp("\\?" + QUERY$) + "?" + subexp("\\#" + FRAGMENT$) + "?"),
                        URI_REFERENCE$ = subexp(URI$ + "|" + RELATIVE$),
                        ABSOLUTE_URI$ = subexp(SCHEME$ + "\\:" + HIER_PART$ + subexp("\\?" + QUERY$) + "?"),
                        GENERIC_REF$ = "^(" + SCHEME$ + ")\\:" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?" + subexp("\\#(" + FRAGMENT$ + ")") + "?$",
                        RELATIVE_REF$ = "^(){0}" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?" + subexp("\\#(" + FRAGMENT$ + ")") + "?$",
                        ABSOLUTE_REF$ = "^(" + SCHEME$ + ")\\:" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?$",
                        SAMEDOC_REF$ = "^" + subexp("\\#(" + FRAGMENT$ + ")") + "?$",
                        AUTHORITY_REF$ = "^" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?$";
                    return {
                        NOT_SCHEME: new RegExp(merge("[^]", ALPHA$$, DIGIT$$, "[\\+\\-\\.]"), "g"),
                        NOT_USERINFO: new RegExp(merge("[^\\%\\:]", UNRESERVED$$, SUB_DELIMS$$), "g"),
                        NOT_HOST: new RegExp(merge("[^\\%\\[\\]\\:]", UNRESERVED$$, SUB_DELIMS$$), "g"),
                        NOT_PATH: new RegExp(merge("[^\\%\\/\\:\\@]", UNRESERVED$$, SUB_DELIMS$$), "g"),
                        NOT_PATH_NOSCHEME: new RegExp(merge("[^\\%\\/\\@]", UNRESERVED$$, SUB_DELIMS$$), "g"),
                        NOT_QUERY: new RegExp(merge("[^\\%]", UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@\\/\\?]", IPRIVATE$$), "g"),
                        NOT_FRAGMENT: new RegExp(merge("[^\\%]", UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@\\/\\?]"), "g"),
                        ESCAPE: new RegExp(merge("[^]", UNRESERVED$$, SUB_DELIMS$$), "g"),
                        UNRESERVED: new RegExp(UNRESERVED$$, "g"),
                        OTHER_CHARS: new RegExp(merge("[^\\%]", UNRESERVED$$, RESERVED$$), "g"),
                        PCT_ENCODED: new RegExp(PCT_ENCODED$, "g"),
                        IPV4ADDRESS: new RegExp("^(" + IPV4ADDRESS$ + ")$"),
                        IPV6ADDRESS: new RegExp("^\\[?(" + IPV6ADDRESS$ + ")" + subexp(subexp("\\%25|\\%(?!" + HEXDIG$$ + "{2})") + "(" + ZONEID$ + ")") + "?\\]?$") //RFC 6874, with relaxed parsing rules
                    };
                }
                var URI_PROTOCOL = buildExps(false);

                var IRI_PROTOCOL = buildExps(true);

                var slicedToArray = function () {
                    function sliceIterator(arr, i) {
                        var _arr = [];
                        var _n = true;
                        var _d = false;
                        var _e = undefined;

                        try {
                            for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
                                _arr.push(_s.value);

                                if (i && _arr.length === i) break;
                            }
                        } catch (err) {
                            _d = true;
                            _e = err;
                        } finally {
                            try {
                                if (!_n && _i["return"]) _i["return"]();
                            } finally {
                                if (_d) throw _e;
                            }
                        }

                        return _arr;
                    }

                    return function (arr, i) {
                        if (Array.isArray(arr)) {
                            return arr;
                        } else if (Symbol.iterator in Object(arr)) {
                            return sliceIterator(arr, i);
                        } else {
                            throw new TypeError("Invalid attempt to destructure non-iterable instance");
                        }
                    };
                }();













                var toConsumableArray = function (arr) {
                    if (Array.isArray(arr)) {
                        for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];

                        return arr2;
                    } else {
                        return Array.from(arr);
                    }
                };

                /** Highest positive signed 32-bit float value */

                var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1

                /** Bootstring parameters */
                var base = 36;
                var tMin = 1;
                var tMax = 26;
                var skew = 38;
                var damp = 700;
                var initialBias = 72;
                var initialN = 128; // 0x80
                var delimiter = '-'; // '\x2D'

                /** Regular expressions */
                var regexPunycode = /^xn--/;
                var regexNonASCII = /[^\0-\x7E]/; // non-ASCII chars
                var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators

                /** Error messages */
                var errors = {
                    'overflow': 'Overflow: input needs wider integers to process',
                    'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
                    'invalid-input': 'Invalid input'
                };

                /** Convenience shortcuts */
                var baseMinusTMin = base - tMin;
                var floor = Math.floor;
                var stringFromCharCode = String.fromCharCode;

                /*--------------------------------------------------------------------------*/

                /**
                 * A generic error utility function.
                 * @private
                 * @param {String} type The error type.
                 * @returns {Error} Throws a `RangeError` with the applicable error message.
                 */
                function error$1(type) {
                    throw new RangeError(errors[type]);
                }

                /**
                 * A generic `Array#map` utility function.
                 * @private
                 * @param {Array} array The array to iterate over.
                 * @param {Function} callback The function that gets called for every array
                 * item.
                 * @returns {Array} A new array of values returned by the callback function.
                 */
                function map(array, fn) {
                    var result = [];
                    var length = array.length;
                    while (length--) {
                        result[length] = fn(array[length]);
                    }
                    return result;
                }

                /**
                 * A simple `Array#map`-like wrapper to work with domain name strings or email
                 * addresses.
                 * @private
                 * @param {String} domain The domain name or email address.
                 * @param {Function} callback The function that gets called for every
                 * character.
                 * @returns {Array} A new string of characters returned by the callback
                 * function.
                 */
                function mapDomain(string, fn) {
                    var parts = string.split('@');
                    var result = '';
                    if (parts.length > 1) {
                        // In email addresses, only the domain name should be punycoded. Leave
                        // the local part (i.e. everything up to `@`) intact.
                        result = parts[0] + '@';
                        string = parts[1];
                    }
                    // Avoid `split(regex)` for IE8 compatibility. See #17.
                    string = string.replace(regexSeparators, '\x2E');
                    var labels = string.split('.');
                    var encoded = map(labels, fn).join('.');
                    return result + encoded;
                }

                /**
                 * Creates an array containing the numeric code points of each Unicode
                 * character in the string. While JavaScript uses UCS-2 internally,
                 * this function will convert a pair of surrogate halves (each of which
                 * UCS-2 exposes as separate characters) into a single code point,
                 * matching UTF-16.
                 * @see `punycode.ucs2.encode`
                 * @see <https://mathiasbynens.be/notes/javascript-encoding>
                 * @memberOf punycode.ucs2
                 * @name decode
                 * @param {String} string The Unicode input string (UCS-2).
                 * @returns {Array} The new array of code points.
                 */
                function ucs2decode(string) {
                    var output = [];
                    var counter = 0;
                    var length = string.length;
                    while (counter < length) {
                        var value = string.charCodeAt(counter++);
                        if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
                            // It's a high surrogate, and there is a next character.
                            var extra = string.charCodeAt(counter++);
                            if ((extra & 0xFC00) == 0xDC00) {
                                // Low surrogate.
                                output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
                            } else {
                                // It's an unmatched surrogate; only append this code unit, in case the
                                // next code unit is the high surrogate of a surrogate pair.
                                output.push(value);
                                counter--;
                            }
                        } else {
                            output.push(value);
                        }
                    }
                    return output;
                }

                /**
                 * Creates a string based on an array of numeric code points.
                 * @see `punycode.ucs2.decode`
                 * @memberOf punycode.ucs2
                 * @name encode
                 * @param {Array} codePoints The array of numeric code points.
                 * @returns {String} The new Unicode string (UCS-2).
                 */
                var ucs2encode = function ucs2encode(array) {
                    return String.fromCodePoint.apply(String, toConsumableArray(array));
                };

                /**
                 * Converts a basic code point into a digit/integer.
                 * @see `digitToBasic()`
                 * @private
                 * @param {Number} codePoint The basic numeric code point value.
                 * @returns {Number} The numeric value of a basic code point (for use in
                 * representing integers) in the range `0` to `base - 1`, or `base` if
                 * the code point does not represent a value.
                 */
                var basicToDigit = function basicToDigit(codePoint) {
                    if (codePoint - 0x30 < 0x0A) {
                        return codePoint - 0x16;
                    }
                    if (codePoint - 0x41 < 0x1A) {
                        return codePoint - 0x41;
                    }
                    if (codePoint - 0x61 < 0x1A) {
                        return codePoint - 0x61;
                    }
                    return base;
                };

                /**
                 * Converts a digit/integer into a basic code point.
                 * @see `basicToDigit()`
                 * @private
                 * @param {Number} digit The numeric value of a basic code point.
                 * @returns {Number} The basic code point whose value (when used for
                 * representing integers) is `digit`, which needs to be in the range
                 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
                 * used; else, the lowercase form is used. The behavior is undefined
                 * if `flag` is non-zero and `digit` has no uppercase form.
                 */
                var digitToBasic = function digitToBasic(digit, flag) {
                    //  0..25 map to ASCII a..z or A..Z
                    // 26..35 map to ASCII 0..9
                    return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
                };

                /**
                 * Bias adaptation function as per section 3.4 of RFC 3492.
                 * https://tools.ietf.org/html/rfc3492#section-3.4
                 * @private
                 */
                var adapt = function adapt(delta, numPoints, firstTime) {
                    var k = 0;
                    delta = firstTime ? floor(delta / damp) : delta >> 1;
                    delta += floor(delta / numPoints);
                    for (; /* no initialization */delta > baseMinusTMin * tMax >> 1; k += base) {
                        delta = floor(delta / baseMinusTMin);
                    }
                    return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
                };

                /**
                 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
                 * symbols.
                 * @memberOf punycode
                 * @param {String} input The Punycode string of ASCII-only symbols.
                 * @returns {String} The resulting string of Unicode symbols.
                 */
                var decode = function decode(input) {
                    // Don't use UCS-2.
                    var output = [];
                    var inputLength = input.length;
                    var i = 0;
                    var n = initialN;
                    var bias = initialBias;

                    // Handle the basic code points: let `basic` be the number of input code
                    // points before the last delimiter, or `0` if there is none, then copy
                    // the first basic code points to the output.

                    var basic = input.lastIndexOf(delimiter);
                    if (basic < 0) {
                        basic = 0;
                    }

                    for (var j = 0; j < basic; ++j) {
                        // if it's not a basic code point
                        if (input.charCodeAt(j) >= 0x80) {
                            error$1('not-basic');
                        }
                        output.push(input.charCodeAt(j));
                    }

                    // Main decoding loop: start just after the last delimiter if any basic code
                    // points were copied; start at the beginning otherwise.

                    for (var index = basic > 0 ? basic + 1 : 0; index < inputLength;) /* no final expression */ {

                        // `index` is the index of the next character to be consumed.
                        // Decode a generalized variable-length integer into `delta`,
                        // which gets added to `i`. The overflow checking is easier
                        // if we increase `i` as we go, then subtract off its starting
                        // value at the end to obtain `delta`.
                        var oldi = i;
                        for (var w = 1, k = base; ; /* no condition */k += base) {

                            if (index >= inputLength) {
                                error$1('invalid-input');
                            }

                            var digit = basicToDigit(input.charCodeAt(index++));

                            if (digit >= base || digit > floor((maxInt - i) / w)) {
                                error$1('overflow');
                            }

                            i += digit * w;
                            var t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;

                            if (digit < t) {
                                break;
                            }

                            var baseMinusT = base - t;
                            if (w > floor(maxInt / baseMinusT)) {
                                error$1('overflow');
                            }

                            w *= baseMinusT;
                        }

                        var out = output.length + 1;
                        bias = adapt(i - oldi, out, oldi == 0);

                        // `i` was supposed to wrap around from `out` to `0`,
                        // incrementing `n` each time, so we'll fix that now:
                        if (floor(i / out) > maxInt - n) {
                            error$1('overflow');
                        }

                        n += floor(i / out);
                        i %= out;

                        // Insert `n` at position `i` of the output.
                        output.splice(i++, 0, n);
                    }

                    return String.fromCodePoint.apply(String, output);
                };

                /**
                 * Converts a string of Unicode symbols (e.g. a domain name label) to a
                 * Punycode string of ASCII-only symbols.
                 * @memberOf punycode
                 * @param {String} input The string of Unicode symbols.
                 * @returns {String} The resulting Punycode string of ASCII-only symbols.
                 */
                var encode = function encode(input) {
                    var output = [];

                    // Convert the input in UCS-2 to an array of Unicode code points.
                    input = ucs2decode(input);

                    // Cache the length.
                    var inputLength = input.length;

                    // Initialize the state.
                    var n = initialN;
                    var delta = 0;
                    var bias = initialBias;

                    // Handle the basic code points.
                    var _iteratorNormalCompletion = true;
                    var _didIteratorError = false;
                    var _iteratorError = undefined;

                    try {
                        for (var _iterator = input[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
                            var _currentValue2 = _step.value;

                            if (_currentValue2 < 0x80) {
                                output.push(stringFromCharCode(_currentValue2));
                            }
                        }
                    } catch (err) {
                        _didIteratorError = true;
                        _iteratorError = err;
                    } finally {
                        try {
                            if (!_iteratorNormalCompletion && _iterator.return) {
                                _iterator.return();
                            }
                        } finally {
                            if (_didIteratorError) {
                                throw _iteratorError;
                            }
                        }
                    }

                    var basicLength = output.length;
                    var handledCPCount = basicLength;

                    // `handledCPCount` is the number of code points that have been handled;
                    // `basicLength` is the number of basic code points.

                    // Finish the basic string with a delimiter unless it's empty.
                    if (basicLength) {
                        output.push(delimiter);
                    }

                    // Main encoding loop:
                    while (handledCPCount < inputLength) {

                        // All non-basic code points < n have been handled already. Find the next
                        // larger one:
                        var m = maxInt;
                        var _iteratorNormalCompletion2 = true;
                        var _didIteratorError2 = false;
                        var _iteratorError2 = undefined;

                        try {
                            for (var _iterator2 = input[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
                                var currentValue = _step2.value;

                                if (currentValue >= n && currentValue < m) {
                                    m = currentValue;
                                }
                            }

                            // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
                            // but guard against overflow.
                        } catch (err) {
                            _didIteratorError2 = true;
                            _iteratorError2 = err;
                        } finally {
                            try {
                                if (!_iteratorNormalCompletion2 && _iterator2.return) {
                                    _iterator2.return();
                                }
                            } finally {
                                if (_didIteratorError2) {
                                    throw _iteratorError2;
                                }
                            }
                        }

                        var handledCPCountPlusOne = handledCPCount + 1;
                        if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
                            error$1('overflow');
                        }

                        delta += (m - n) * handledCPCountPlusOne;
                        n = m;

                        var _iteratorNormalCompletion3 = true;
                        var _didIteratorError3 = false;
                        var _iteratorError3 = undefined;

                        try {
                            for (var _iterator3 = input[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
                                var _currentValue = _step3.value;

                                if (_currentValue < n && ++delta > maxInt) {
                                    error$1('overflow');
                                }
                                if (_currentValue == n) {
                                    // Represent delta as a generalized variable-length integer.
                                    var q = delta;
                                    for (var k = base; ; /* no condition */k += base) {
                                        var t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
                                        if (q < t) {
                                            break;
                                        }
                                        var qMinusT = q - t;
                                        var baseMinusT = base - t;
                                        output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)));
                                        q = floor(qMinusT / baseMinusT);
                                    }

                                    output.push(stringFromCharCode(digitToBasic(q, 0)));
                                    bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
                                    delta = 0;
                                    ++handledCPCount;
                                }
                            }
                        } catch (err) {
                            _didIteratorError3 = true;
                            _iteratorError3 = err;
                        } finally {
                            try {
                                if (!_iteratorNormalCompletion3 && _iterator3.return) {
                                    _iterator3.return();
                                }
                            } finally {
                                if (_didIteratorError3) {
                                    throw _iteratorError3;
                                }
                            }
                        }

                        ++delta;
                        ++n;
                    }
                    return output.join('');
                };

                /**
                 * Converts a Punycode string representing a domain name or an email address
                 * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
                 * it doesn't matter if you call it on a string that has already been
                 * converted to Unicode.
                 * @memberOf punycode
                 * @param {String} input The Punycoded domain name or email address to
                 * convert to Unicode.
                 * @returns {String} The Unicode representation of the given Punycode
                 * string.
                 */
                var toUnicode = function toUnicode(input) {
                    return mapDomain(input, function (string) {
                        return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string;
                    });
                };

                /**
                 * Converts a Unicode string representing a domain name or an email address to
                 * Punycode. Only the non-ASCII parts of the domain name will be converted,
                 * i.e. it doesn't matter if you call it with a domain that's already in
                 * ASCII.
                 * @memberOf punycode
                 * @param {String} input The domain name or email address to convert, as a
                 * Unicode string.
                 * @returns {String} The Punycode representation of the given domain name or
                 * email address.
                 */
                var toASCII = function toASCII(input) {
                    return mapDomain(input, function (string) {
                        return regexNonASCII.test(string) ? 'xn--' + encode(string) : string;
                    });
                };

                /*--------------------------------------------------------------------------*/

                /** Define the public API */
                var punycode = {
                    /**
                  * A string representing the current Punycode.js version number.
                  * @memberOf punycode
                  * @type String
                  */
                    'version': '2.1.0',
                    /**
                  * An object of methods to convert from JavaScript's internal character
                  * representation (UCS-2) to Unicode code points, and back.
                  * @see <https://mathiasbynens.be/notes/javascript-encoding>
                  * @memberOf punycode
                  * @type Object
                  */
                    'ucs2': {
                        'decode': ucs2decode,
                        'encode': ucs2encode
                    },
                    'decode': decode,
                    'encode': encode,
                    'toASCII': toASCII,
                    'toUnicode': toUnicode
                };

                /**
                 * URI.js
                 *
                 * @fileoverview An RFC 3986 compliant, scheme extendable URI parsing/validating/resolving library for JavaScript.
                 * @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
                 * @see http://github.com/garycourt/uri-js
                 */
                /**
                 * Copyright 2011 Gary Court. All rights reserved.
                 *
                 * Redistribution and use in source and binary forms, with or without modification, are
                 * permitted provided that the following conditions are met:
                 *
                 *    1. Redistributions of source code must retain the above copyright notice, this list of
                 *       conditions and the following disclaimer.
                 *
                 *    2. Redistributions in binary form must reproduce the above copyright notice, this list
                 *       of conditions and the following disclaimer in the documentation and/or other materials
                 *       provided with the distribution.
                 *
                 * THIS SOFTWARE IS PROVIDED BY GARY COURT ``AS IS'' AND ANY EXPRESS OR IMPLIED
                 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
                 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR
                 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
                 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
                 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                 *
                 * The views and conclusions contained in the software and documentation are those of the
                 * authors and should not be interpreted as representing official policies, either expressed
                 * or implied, of Gary Court.
                 */
                var SCHEMES = {};
                function pctEncChar(chr) {
                    var c = chr.charCodeAt(0);
                    var e = void 0;
                    if (c < 16) e = "%0" + c.toString(16).toUpperCase(); else if (c < 128) e = "%" + c.toString(16).toUpperCase(); else if (c < 2048) e = "%" + (c >> 6 | 192).toString(16).toUpperCase() + "%" + (c & 63 | 128).toString(16).toUpperCase(); else e = "%" + (c >> 12 | 224).toString(16).toUpperCase() + "%" + (c >> 6 & 63 | 128).toString(16).toUpperCase() + "%" + (c & 63 | 128).toString(16).toUpperCase();
                    return e;
                }
                function pctDecChars(str) {
                    var newStr = "";
                    var i = 0;
                    var il = str.length;
                    while (i < il) {
                        var c = parseInt(str.substr(i + 1, 2), 16);
                        if (c < 128) {
                            newStr += String.fromCharCode(c);
                            i += 3;
                        } else if (c >= 194 && c < 224) {
                            if (il - i >= 6) {
                                var c2 = parseInt(str.substr(i + 4, 2), 16);
                                newStr += String.fromCharCode((c & 31) << 6 | c2 & 63);
                            } else {
                                newStr += str.substr(i, 6);
                            }
                            i += 6;
                        } else if (c >= 224) {
                            if (il - i >= 9) {
                                var _c = parseInt(str.substr(i + 4, 2), 16);
                                var c3 = parseInt(str.substr(i + 7, 2), 16);
                                newStr += String.fromCharCode((c & 15) << 12 | (_c & 63) << 6 | c3 & 63);
                            } else {
                                newStr += str.substr(i, 9);
                            }
                            i += 9;
                        } else {
                            newStr += str.substr(i, 3);
                            i += 3;
                        }
                    }
                    return newStr;
                }
                function _normalizeComponentEncoding(components, protocol) {
                    function decodeUnreserved(str) {
                        var decStr = pctDecChars(str);
                        return !decStr.match(protocol.UNRESERVED) ? str : decStr;
                    }
                    if (components.scheme) components.scheme = String(components.scheme).replace(protocol.PCT_ENCODED, decodeUnreserved).toLowerCase().replace(protocol.NOT_SCHEME, "");
                    if (components.userinfo !== undefined) components.userinfo = String(components.userinfo).replace(protocol.PCT_ENCODED, decodeUnreserved).replace(protocol.NOT_USERINFO, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase);
                    if (components.host !== undefined) components.host = String(components.host).replace(protocol.PCT_ENCODED, decodeUnreserved).toLowerCase().replace(protocol.NOT_HOST, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase);
                    if (components.path !== undefined) components.path = String(components.path).replace(protocol.PCT_ENCODED, decodeUnreserved).replace(components.scheme ? protocol.NOT_PATH : protocol.NOT_PATH_NOSCHEME, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase);
                    if (components.query !== undefined) components.query = String(components.query).replace(protocol.PCT_ENCODED, decodeUnreserved).replace(protocol.NOT_QUERY, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase);
                    if (components.fragment !== undefined) components.fragment = String(components.fragment).replace(protocol.PCT_ENCODED, decodeUnreserved).replace(protocol.NOT_FRAGMENT, pctEncChar).replace(protocol.PCT_ENCODED, toUpperCase);
                    return components;
                }

                function _stripLeadingZeros(str) {
                    return str.replace(/^0*(.*)/, "$1") || "0";
                }
                function _normalizeIPv4(host, protocol) {
                    var matches = host.match(protocol.IPV4ADDRESS) || [];

                    var _matches = slicedToArray(matches, 2),
                        address = _matches[1];

                    if (address) {
                        return address.split(".").map(_stripLeadingZeros).join(".");
                    } else {
                        return host;
                    }
                }
                function _normalizeIPv6(host, protocol) {
                    var matches = host.match(protocol.IPV6ADDRESS) || [];

                    var _matches2 = slicedToArray(matches, 3),
                        address = _matches2[1],
                        zone = _matches2[2];

                    if (address) {
                        var _address$toLowerCase$ = address.toLowerCase().split('::').reverse(),
                            _address$toLowerCase$2 = slicedToArray(_address$toLowerCase$, 2),
                            last = _address$toLowerCase$2[0],
                            first = _address$toLowerCase$2[1];

                        var firstFields = first ? first.split(":").map(_stripLeadingZeros) : [];
                        var lastFields = last.split(":").map(_stripLeadingZeros);
                        var isLastFieldIPv4Address = protocol.IPV4ADDRESS.test(lastFields[lastFields.length - 1]);
                        var fieldCount = isLastFieldIPv4Address ? 7 : 8;
                        var lastFieldsStart = lastFields.length - fieldCount;
                        var fields = Array(fieldCount);
                        for (var x = 0; x < fieldCount; ++x) {
                            fields[x] = firstFields[x] || lastFields[lastFieldsStart + x] || '';
                        }
                        if (isLastFieldIPv4Address) {
                            fields[fieldCount - 1] = _normalizeIPv4(fields[fieldCount - 1], protocol);
                        }
                        var allZeroFields = fields.reduce(function (acc, field, index) {
                            if (!field || field === "0") {
                                var lastLongest = acc[acc.length - 1];
                                if (lastLongest && lastLongest.index + lastLongest.length === index) {
                                    lastLongest.length++;
                                } else {
                                    acc.push({ index: index, length: 1 });
                                }
                            }
                            return acc;
                        }, []);
                        var longestZeroFields = allZeroFields.sort(function (a, b) {
                            return b.length - a.length;
                        })[0];
                        var newHost = void 0;
                        if (longestZeroFields && longestZeroFields.length > 1) {
                            var newFirst = fields.slice(0, longestZeroFields.index);
                            var newLast = fields.slice(longestZeroFields.index + longestZeroFields.length);
                            newHost = newFirst.join(":") + "::" + newLast.join(":");
                        } else {
                            newHost = fields.join(":");
                        }
                        if (zone) {
                            newHost += "%" + zone;
                        }
                        return newHost;
                    } else {
                        return host;
                    }
                }
                var URI_PARSE = /^(?:([^:\/?#]+):)?(?:\/\/((?:([^\/?#@]*)@)?(\[[^\/?#\]]+\]|[^\/?#:]*)(?:\:(\d*))?))?([^?#]*)(?:\?([^#]*))?(?:#((?:.|\n|\r)*))?/i;
                var NO_MATCH_IS_UNDEFINED = "".match(/(){0}/)[1] === undefined;
                function parse(uriString) {
                    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

                    var components = {};
                    var protocol = options.iri !== false ? IRI_PROTOCOL : URI_PROTOCOL;
                    if (options.reference === "suffix") uriString = (options.scheme ? options.scheme + ":" : "") + "//" + uriString;
                    var matches = uriString.match(URI_PARSE);
                    if (matches) {
                        if (NO_MATCH_IS_UNDEFINED) {
                            //store each component
                            components.scheme = matches[1];
                            components.userinfo = matches[3];
                            components.host = matches[4];
                            components.port = parseInt(matches[5], 10);
                            components.path = matches[6] || "";
                            components.query = matches[7];
                            components.fragment = matches[8];
                            //fix port number
                            if (isNaN(components.port)) {
                                components.port = matches[5];
                            }
                        } else {
                            //IE FIX for improper RegExp matching
                            //store each component
                            components.scheme = matches[1] || undefined;
                            components.userinfo = uriString.indexOf("@") !== -1 ? matches[3] : undefined;
                            components.host = uriString.indexOf("//") !== -1 ? matches[4] : undefined;
                            components.port = parseInt(matches[5], 10);
                            components.path = matches[6] || "";
                            components.query = uriString.indexOf("?") !== -1 ? matches[7] : undefined;
                            components.fragment = uriString.indexOf("#") !== -1 ? matches[8] : undefined;
                            //fix port number
                            if (isNaN(components.port)) {
                                components.port = uriString.match(/\/\/(?:.|\n)*\:(?:\/|\?|\#|$)/) ? matches[4] : undefined;
                            }
                        }
                        if (components.host) {
                            //normalize IP hosts
                            components.host = _normalizeIPv6(_normalizeIPv4(components.host, protocol), protocol);
                        }
                        //determine reference type
                        if (components.scheme === undefined && components.userinfo === undefined && components.host === undefined && components.port === undefined && !components.path && components.query === undefined) {
                            components.reference = "same-document";
                        } else if (components.scheme === undefined) {
                            components.reference = "relative";
                        } else if (components.fragment === undefined) {
                            components.reference = "absolute";
                        } else {
                            components.reference = "uri";
                        }
                        //check for reference errors
                        if (options.reference && options.reference !== "suffix" && options.reference !== components.reference) {
                            components.error = components.error || "URI is not a " + options.reference + " reference.";
                        }
                        //find scheme handler
                        var schemeHandler = SCHEMES[(options.scheme || components.scheme || "").toLowerCase()];
                        //check if scheme can't handle IRIs
                        if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
                            //if host component is a domain name
                            if (components.host && (options.domainHost || schemeHandler && schemeHandler.domainHost)) {
                                //convert Unicode IDN -> ASCII IDN
                                try {
                                    components.host = punycode.toASCII(components.host.replace(protocol.PCT_ENCODED, pctDecChars).toLowerCase());
                                } catch (e) {
                                    components.error = components.error || "Host's domain name can not be converted to ASCII via punycode: " + e;
                                }
                            }
                            //convert IRI -> URI
                            _normalizeComponentEncoding(components, URI_PROTOCOL);
                        } else {
                            //normalize encodings
                            _normalizeComponentEncoding(components, protocol);
                        }
                        //perform scheme specific parsing
                        if (schemeHandler && schemeHandler.parse) {
                            schemeHandler.parse(components, options);
                        }
                    } else {
                        components.error = components.error || "URI can not be parsed.";
                    }
                    return components;
                }

                function _recomposeAuthority(components, options) {
                    var protocol = options.iri !== false ? IRI_PROTOCOL : URI_PROTOCOL;
                    var uriTokens = [];
                    if (components.userinfo !== undefined) {
                        uriTokens.push(components.userinfo);
                        uriTokens.push("@");
                    }
                    if (components.host !== undefined) {
                        //normalize IP hosts, add brackets and escape zone separator for IPv6
                        uriTokens.push(_normalizeIPv6(_normalizeIPv4(String(components.host), protocol), protocol).replace(protocol.IPV6ADDRESS, function (_, $1, $2) {
                            return "[" + $1 + ($2 ? "%25" + $2 : "") + "]";
                        }));
                    }
                    if (typeof components.port === "number" || typeof components.port === "string") {
                        uriTokens.push(":");
                        uriTokens.push(String(components.port));
                    }
                    return uriTokens.length ? uriTokens.join("") : undefined;
                }

                var RDS1 = /^\.\.?\//;
                var RDS2 = /^\/\.(\/|$)/;
                var RDS3 = /^\/\.\.(\/|$)/;
                var RDS5 = /^\/?(?:.|\n)*?(?=\/|$)/;
                function removeDotSegments(input) {
                    var output = [];
                    while (input.length) {
                        if (input.match(RDS1)) {
                            input = input.replace(RDS1, "");
                        } else if (input.match(RDS2)) {
                            input = input.replace(RDS2, "/");
                        } else if (input.match(RDS3)) {
                            input = input.replace(RDS3, "/");
                            output.pop();
                        } else if (input === "." || input === "..") {
                            input = "";
                        } else {
                            var im = input.match(RDS5);
                            if (im) {
                                var s = im[0];
                                input = input.slice(s.length);
                                output.push(s);
                            } else {
                                throw new Error("Unexpected dot segment condition");
                            }
                        }
                    }
                    return output.join("");
                }

                function serialize(components) {
                    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

                    var protocol = options.iri ? IRI_PROTOCOL : URI_PROTOCOL;
                    var uriTokens = [];
                    //find scheme handler
                    var schemeHandler = SCHEMES[(options.scheme || components.scheme || "").toLowerCase()];
                    //perform scheme specific serialization
                    if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(components, options);
                    if (components.host) {
                        //if host component is an IPv6 address
                        if (protocol.IPV6ADDRESS.test(components.host)) { }
                        //TODO: normalize IPv6 address as per RFC 5952

                        //if host component is a domain name
                        else if (options.domainHost || schemeHandler && schemeHandler.domainHost) {
                            //convert IDN via punycode
                            try {
                                components.host = !options.iri ? punycode.toASCII(components.host.replace(protocol.PCT_ENCODED, pctDecChars).toLowerCase()) : punycode.toUnicode(components.host);
                            } catch (e) {
                                components.error = components.error || "Host's domain name can not be converted to " + (!options.iri ? "ASCII" : "Unicode") + " via punycode: " + e;
                            }
                        }
                    }
                    //normalize encoding
                    _normalizeComponentEncoding(components, protocol);
                    if (options.reference !== "suffix" && components.scheme) {
                        uriTokens.push(components.scheme);
                        uriTokens.push(":");
                    }
                    var authority = _recomposeAuthority(components, options);
                    if (authority !== undefined) {
                        if (options.reference !== "suffix") {
                            uriTokens.push("//");
                        }
                        uriTokens.push(authority);
                        if (components.path && components.path.charAt(0) !== "/") {
                            uriTokens.push("/");
                        }
                    }
                    if (components.path !== undefined) {
                        var s = components.path;
                        if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
                            s = removeDotSegments(s);
                        }
                        if (authority === undefined) {
                            s = s.replace(/^\/\//, "/%2F"); //don't allow the path to start with "//"
                        }
                        uriTokens.push(s);
                    }
                    if (components.query !== undefined) {
                        uriTokens.push("?");
                        uriTokens.push(components.query);
                    }
                    if (components.fragment !== undefined) {
                        uriTokens.push("#");
                        uriTokens.push(components.fragment);
                    }
                    return uriTokens.join(""); //merge tokens into a string
                }

                function resolveComponents(base, relative) {
                    var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
                    var skipNormalization = arguments[3];

                    var target = {};
                    if (!skipNormalization) {
                        base = parse(serialize(base, options), options); //normalize base components
                        relative = parse(serialize(relative, options), options); //normalize relative components
                    }
                    options = options || {};
                    if (!options.tolerant && relative.scheme) {
                        target.scheme = relative.scheme;
                        //target.authority = relative.authority;
                        target.userinfo = relative.userinfo;
                        target.host = relative.host;
                        target.port = relative.port;
                        target.path = removeDotSegments(relative.path || "");
                        target.query = relative.query;
                    } else {
                        if (relative.userinfo !== undefined || relative.host !== undefined || relative.port !== undefined) {
                            //target.authority = relative.authority;
                            target.userinfo = relative.userinfo;
                            target.host = relative.host;
                            target.port = relative.port;
                            target.path = removeDotSegments(relative.path || "");
                            target.query = relative.query;
                        } else {
                            if (!relative.path) {
                                target.path = base.path;
                                if (relative.query !== undefined) {
                                    target.query = relative.query;
                                } else {
                                    target.query = base.query;
                                }
                            } else {
                                if (relative.path.charAt(0) === "/") {
                                    target.path = removeDotSegments(relative.path);
                                } else {
                                    if ((base.userinfo !== undefined || base.host !== undefined || base.port !== undefined) && !base.path) {
                                        target.path = "/" + relative.path;
                                    } else if (!base.path) {
                                        target.path = relative.path;
                                    } else {
                                        target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative.path;
                                    }
                                    target.path = removeDotSegments(target.path);
                                }
                                target.query = relative.query;
                            }
                            //target.authority = base.authority;
                            target.userinfo = base.userinfo;
                            target.host = base.host;
                            target.port = base.port;
                        }
                        target.scheme = base.scheme;
                    }
                    target.fragment = relative.fragment;
                    return target;
                }

                function resolve(baseURI, relativeURI, options) {
                    var schemelessOptions = assign({ scheme: 'null' }, options);
                    return serialize(resolveComponents(parse(baseURI, schemelessOptions), parse(relativeURI, schemelessOptions), schemelessOptions, true), schemelessOptions);
                }

                function normalize(uri, options) {
                    if (typeof uri === "string") {
                        uri = serialize(parse(uri, options), options);
                    } else if (typeOf(uri) === "object") {
                        uri = parse(serialize(uri, options), options);
                    }
                    return uri;
                }

                function equal(uriA, uriB, options) {
                    if (typeof uriA === "string") {
                        uriA = serialize(parse(uriA, options), options);
                    } else if (typeOf(uriA) === "object") {
                        uriA = serialize(uriA, options);
                    }
                    if (typeof uriB === "string") {
                        uriB = serialize(parse(uriB, options), options);
                    } else if (typeOf(uriB) === "object") {
                        uriB = serialize(uriB, options);
                    }
                    return uriA === uriB;
                }

                function escapeComponent(str, options) {
                    return str && str.toString().replace(!options || !options.iri ? URI_PROTOCOL.ESCAPE : IRI_PROTOCOL.ESCAPE, pctEncChar);
                }

                function unescapeComponent(str, options) {
                    return str && str.toString().replace(!options || !options.iri ? URI_PROTOCOL.PCT_ENCODED : IRI_PROTOCOL.PCT_ENCODED, pctDecChars);
                }

                var handler = {
                    scheme: "http",
                    domainHost: true,
                    parse: function parse(components, options) {
                        //report missing host
                        if (!components.host) {
                            components.error = components.error || "HTTP URIs must have a host.";
                        }
                        return components;
                    },
                    serialize: function serialize(components, options) {
                        var secure = String(components.scheme).toLowerCase() === "https";
                        //normalize the default port
                        if (components.port === (secure ? 443 : 80) || components.port === "") {
                            components.port = undefined;
                        }
                        //normalize the empty path
                        if (!components.path) {
                            components.path = "/";
                        }
                        //NOTE: We do not parse query strings for HTTP URIs
                        //as WWW Form Url Encoded query strings are part of the HTML4+ spec,
                        //and not the HTTP spec.
                        return components;
                    }
                };

                var handler$1 = {
                    scheme: "https",
                    domainHost: handler.domainHost,
                    parse: handler.parse,
                    serialize: handler.serialize
                };

                function isSecure(wsComponents) {
                    return typeof wsComponents.secure === 'boolean' ? wsComponents.secure : String(wsComponents.scheme).toLowerCase() === "wss";
                }
                //RFC 6455
                var handler$2 = {
                    scheme: "ws",
                    domainHost: true,
                    parse: function parse(components, options) {
                        var wsComponents = components;
                        //indicate if the secure flag is set
                        wsComponents.secure = isSecure(wsComponents);
                        //construct resouce name
                        wsComponents.resourceName = (wsComponents.path || '/') + (wsComponents.query ? '?' + wsComponents.query : '');
                        wsComponents.path = undefined;
                        wsComponents.query = undefined;
                        return wsComponents;
                    },
                    serialize: function serialize(wsComponents, options) {
                        //normalize the default port
                        if (wsComponents.port === (isSecure(wsComponents) ? 443 : 80) || wsComponents.port === "") {
                            wsComponents.port = undefined;
                        }
                        //ensure scheme matches secure flag
                        if (typeof wsComponents.secure === 'boolean') {
                            wsComponents.scheme = wsComponents.secure ? 'wss' : 'ws';
                            wsComponents.secure = undefined;
                        }
                        //reconstruct path from resource name
                        if (wsComponents.resourceName) {
                            var _wsComponents$resourc = wsComponents.resourceName.split('?'),
                                _wsComponents$resourc2 = slicedToArray(_wsComponents$resourc, 2),
                                path = _wsComponents$resourc2[0],
                                query = _wsComponents$resourc2[1];

                            wsComponents.path = path && path !== '/' ? path : undefined;
                            wsComponents.query = query;
                            wsComponents.resourceName = undefined;
                        }
                        //forbid fragment component
                        wsComponents.fragment = undefined;
                        return wsComponents;
                    }
                };

                var handler$3 = {
                    scheme: "wss",
                    domainHost: handler$2.domainHost,
                    parse: handler$2.parse,
                    serialize: handler$2.serialize
                };

                var O = {};
                var isIRI = true;
                //RFC 3986
                var UNRESERVED$$ = "[A-Za-z0-9\\-\\.\\_\\~" + (isIRI ? "\\xA0-\\u200D\\u2010-\\u2029\\u202F-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF" : "") + "]";
                var HEXDIG$$ = "[0-9A-Fa-f]"; //case-insensitive
                var PCT_ENCODED$ = subexp(subexp("%[EFef]" + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$) + "|" + subexp("%[89A-Fa-f]" + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$) + "|" + subexp("%" + HEXDIG$$ + HEXDIG$$)); //expanded
                //RFC 5322, except these symbols as per RFC 6068: @ : / ? # [ ] & ; =
                //const ATEXT$$ = "[A-Za-z0-9\\!\\#\\$\\%\\&\\'\\*\\+\\-\\/\\=\\?\\^\\_\\`\\{\\|\\}\\~]";
                //const WSP$$ = "[\\x20\\x09]";
                //const OBS_QTEXT$$ = "[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]";  //(%d1-8 / %d11-12 / %d14-31 / %d127)
                //const QTEXT$$ = merge("[\\x21\\x23-\\x5B\\x5D-\\x7E]", OBS_QTEXT$$);  //%d33 / %d35-91 / %d93-126 / obs-qtext
                //const VCHAR$$ = "[\\x21-\\x7E]";
                //const WSP$$ = "[\\x20\\x09]";
                //const OBS_QP$ = subexp("\\\\" + merge("[\\x00\\x0D\\x0A]", OBS_QTEXT$$));  //%d0 / CR / LF / obs-qtext
                //const FWS$ = subexp(subexp(WSP$$ + "*" + "\\x0D\\x0A") + "?" + WSP$$ + "+");
                //const QUOTED_PAIR$ = subexp(subexp("\\\\" + subexp(VCHAR$$ + "|" + WSP$$)) + "|" + OBS_QP$);
                //const QUOTED_STRING$ = subexp('\\"' + subexp(FWS$ + "?" + QCONTENT$) + "*" + FWS$ + "?" + '\\"');
                var ATEXT$$ = "[A-Za-z0-9\\!\\$\\%\\'\\*\\+\\-\\^\\_\\`\\{\\|\\}\\~]";
                var QTEXT$$ = "[\\!\\$\\%\\'\\(\\)\\*\\+\\,\\-\\.0-9\\<\\>A-Z\\x5E-\\x7E]";
                var VCHAR$$ = merge(QTEXT$$, "[\\\"\\\\]");
                var SOME_DELIMS$$ = "[\\!\\$\\'\\(\\)\\*\\+\\,\\;\\:\\@]";
                var UNRESERVED = new RegExp(UNRESERVED$$, "g");
                var PCT_ENCODED = new RegExp(PCT_ENCODED$, "g");
                var NOT_LOCAL_PART = new RegExp(merge("[^]", ATEXT$$, "[\\.]", '[\\"]', VCHAR$$), "g");
                var NOT_HFNAME = new RegExp(merge("[^]", UNRESERVED$$, SOME_DELIMS$$), "g");
                var NOT_HFVALUE = NOT_HFNAME;
                function decodeUnreserved(str) {
                    var decStr = pctDecChars(str);
                    return !decStr.match(UNRESERVED) ? str : decStr;
                }
                var handler$4 = {
                    scheme: "mailto",
                    parse: function parse$$1(components, options) {
                        var mailtoComponents = components;
                        var to = mailtoComponents.to = mailtoComponents.path ? mailtoComponents.path.split(",") : [];
                        mailtoComponents.path = undefined;
                        if (mailtoComponents.query) {
                            var unknownHeaders = false;
                            var headers = {};
                            var hfields = mailtoComponents.query.split("&");
                            for (var x = 0, xl = hfields.length; x < xl; ++x) {
                                var hfield = hfields[x].split("=");
                                switch (hfield[0]) {
                                    case "to":
                                        var toAddrs = hfield[1].split(",");
                                        for (var _x = 0, _xl = toAddrs.length; _x < _xl; ++_x) {
                                            to.push(toAddrs[_x]);
                                        }
                                        break;
                                    case "subject":
                                        mailtoComponents.subject = unescapeComponent(hfield[1], options);
                                        break;
                                    case "body":
                                        mailtoComponents.body = unescapeComponent(hfield[1], options);
                                        break;
                                    default:
                                        unknownHeaders = true;
                                        headers[unescapeComponent(hfield[0], options)] = unescapeComponent(hfield[1], options);
                                        break;
                                }
                            }
                            if (unknownHeaders) mailtoComponents.headers = headers;
                        }
                        mailtoComponents.query = undefined;
                        for (var _x2 = 0, _xl2 = to.length; _x2 < _xl2; ++_x2) {
                            var addr = to[_x2].split("@");
                            addr[0] = unescapeComponent(addr[0]);
                            if (!options.unicodeSupport) {
                                //convert Unicode IDN -> ASCII IDN
                                try {
                                    addr[1] = punycode.toASCII(unescapeComponent(addr[1], options).toLowerCase());
                                } catch (e) {
                                    mailtoComponents.error = mailtoComponents.error || "Email address's domain name can not be converted to ASCII via punycode: " + e;
                                }
                            } else {
                                addr[1] = unescapeComponent(addr[1], options).toLowerCase();
                            }
                            to[_x2] = addr.join("@");
                        }
                        return mailtoComponents;
                    },
                    serialize: function serialize$$1(mailtoComponents, options) {
                        var components = mailtoComponents;
                        var to = toArray(mailtoComponents.to);
                        if (to) {
                            for (var x = 0, xl = to.length; x < xl; ++x) {
                                var toAddr = String(to[x]);
                                var atIdx = toAddr.lastIndexOf("@");
                                var localPart = toAddr.slice(0, atIdx).replace(PCT_ENCODED, decodeUnreserved).replace(PCT_ENCODED, toUpperCase).replace(NOT_LOCAL_PART, pctEncChar);
                                var domain = toAddr.slice(atIdx + 1);
                                //convert IDN via punycode
                                try {
                                    domain = !options.iri ? punycode.toASCII(unescapeComponent(domain, options).toLowerCase()) : punycode.toUnicode(domain);
                                } catch (e) {
                                    components.error = components.error || "Email address's domain name can not be converted to " + (!options.iri ? "ASCII" : "Unicode") + " via punycode: " + e;
                                }
                                to[x] = localPart + "@" + domain;
                            }
                            components.path = to.join(",");
                        }
                        var headers = mailtoComponents.headers = mailtoComponents.headers || {};
                        if (mailtoComponents.subject) headers["subject"] = mailtoComponents.subject;
                        if (mailtoComponents.body) headers["body"] = mailtoComponents.body;
                        var fields = [];
                        for (var name in headers) {
                            if (headers[name] !== O[name]) {
                                fields.push(name.replace(PCT_ENCODED, decodeUnreserved).replace(PCT_ENCODED, toUpperCase).replace(NOT_HFNAME, pctEncChar) + "=" + headers[name].replace(PCT_ENCODED, decodeUnreserved).replace(PCT_ENCODED, toUpperCase).replace(NOT_HFVALUE, pctEncChar));
                            }
                        }
                        if (fields.length) {
                            components.query = fields.join("&");
                        }
                        return components;
                    }
                };

                var URN_PARSE = /^([^\:]+)\:(.*)/;
                //RFC 2141
                var handler$5 = {
                    scheme: "urn",
                    parse: function parse$$1(components, options) {
                        var matches = components.path && components.path.match(URN_PARSE);
                        var urnComponents = components;
                        if (matches) {
                            var scheme = options.scheme || urnComponents.scheme || "urn";
                            var nid = matches[1].toLowerCase();
                            var nss = matches[2];
                            var urnScheme = scheme + ":" + (options.nid || nid);
                            var schemeHandler = SCHEMES[urnScheme];
                            urnComponents.nid = nid;
                            urnComponents.nss = nss;
                            urnComponents.path = undefined;
                            if (schemeHandler) {
                                urnComponents = schemeHandler.parse(urnComponents, options);
                            }
                        } else {
                            urnComponents.error = urnComponents.error || "URN can not be parsed.";
                        }
                        return urnComponents;
                    },
                    serialize: function serialize$$1(urnComponents, options) {
                        var scheme = options.scheme || urnComponents.scheme || "urn";
                        var nid = urnComponents.nid;
                        var urnScheme = scheme + ":" + (options.nid || nid);
                        var schemeHandler = SCHEMES[urnScheme];
                        if (schemeHandler) {
                            urnComponents = schemeHandler.serialize(urnComponents, options);
                        }
                        var uriComponents = urnComponents;
                        var nss = urnComponents.nss;
                        uriComponents.path = (nid || options.nid) + ":" + nss;
                        return uriComponents;
                    }
                };

                var UUID = /^[0-9A-Fa-f]{8}(?:\-[0-9A-Fa-f]{4}){3}\-[0-9A-Fa-f]{12}$/;
                //RFC 4122
                var handler$6 = {
                    scheme: "urn:uuid",
                    parse: function parse(urnComponents, options) {
                        var uuidComponents = urnComponents;
                        uuidComponents.uuid = uuidComponents.nss;
                        uuidComponents.nss = undefined;
                        if (!options.tolerant && (!uuidComponents.uuid || !uuidComponents.uuid.match(UUID))) {
                            uuidComponents.error = uuidComponents.error || "UUID is not valid.";
                        }
                        return uuidComponents;
                    },
                    serialize: function serialize(uuidComponents, options) {
                        var urnComponents = uuidComponents;
                        //normalize UUID
                        urnComponents.nss = (uuidComponents.uuid || "").toLowerCase();
                        return urnComponents;
                    }
                };

                SCHEMES[handler.scheme] = handler;
                SCHEMES[handler$1.scheme] = handler$1;
                SCHEMES[handler$2.scheme] = handler$2;
                SCHEMES[handler$3.scheme] = handler$3;
                SCHEMES[handler$4.scheme] = handler$4;
                SCHEMES[handler$5.scheme] = handler$5;
                SCHEMES[handler$6.scheme] = handler$6;

                exports.SCHEMES = SCHEMES;
                exports.pctEncChar = pctEncChar;
                exports.pctDecChars = pctDecChars;
                exports.parse = parse;
                exports.removeDotSegments = removeDotSegments;
                exports.serialize = serialize;
                exports.resolveComponents = resolveComponents;
                exports.resolve = resolve;
                exports.normalize = normalize;
                exports.equal = equal;
                exports.escapeComponent = escapeComponent;
                exports.unescapeComponent = unescapeComponent;

                Object.defineProperty(exports, '__esModule', { value: true });

            })));


        }, {}]
    }, {}, [34])(34)
});
