text: 
  exports.mixin = function(_){
  
    var BIND_FLAG = 1,
        BIND_KEY_FLAG = 2,
        CURRY_BOUND_FLAG = 4,
        CURRY_FLAG = 8,
        CURRY_RIGHT_FLAG = 16,
        PARTIAL_FLAG = 32,
        PARTIAL_RIGHT_FLAG = 64,
        ARY_FLAG = 128,
        REARG_FLAG = 256,
        FLIP_FLAG = 512;
  
      /**
       * 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 _
       * @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 functions 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 = createWrapper(func, CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
        result.placeholder = curry.placeholder;
        return result;
      }
  
  
      /**
       * lodash 4.0.2 (Custom Build) <https://lodash.com/>
       * Build: `lodash modularize exports="npm" -o ./`
       * Copyright 2012-2016 The Dojo Foundation <http://dojofoundation.org/>
       * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
       * Copyright 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
       * Available under MIT license <https://lodash.com/license>
       */
  
      /** Used as the `TypeError` message for "Functions" methods. */
      var FUNC_ERROR_TEXT = 'Expected a function';
  
      /** Used as the internal argument placeholder. */
      var PLACEHOLDER = '__lodash_placeholder__';
  
      /** Used to compose bitmasks for wrapper metadata. */
      var BIND_FLAG = 1,
          BIND_KEY_FLAG = 2,
          CURRY_BOUND_FLAG = 4,
          CURRY_FLAG = 8,
          CURRY_RIGHT_FLAG = 16,
          PARTIAL_FLAG = 32,
          PARTIAL_RIGHT_FLAG = 64,
          ARY_FLAG = 128,
          FLIP_FLAG = 512;
  
      /** Used as references for various `Number` constants. */
      var INFINITY = 1 / 0,
          MAX_SAFE_INTEGER = 9007199254740991,
          MAX_INTEGER = 1.7976931348623157e+308,
          NAN = 0 / 0;
  
      /** `Object#toString` result references. */
      var funcTag = '[object Function]',
          genTag = '[object GeneratorFunction]';
  
      /** Used to match leading and trailing whitespace. */
      var reTrim = /^\s+|\s+$/g;
  
      /** 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 octal string values. */
      var reIsOctal = /^0o[0-7]+$/i;
  
      /** Used to detect unsigned integer values. */
      var reIsUint = /^(?:0|[1-9]\d*)$/;
  
      /** Used to determine if values are of the language type `Object`. */
      var objectTypes = {
        'function': true,
        'object': true
      };
  
      /** Built-in method references without a dependency on `root`. */
      var freeParseInt = parseInt;
  
      /** Detect free variable `exports`. */
      var freeExports = (objectTypes[typeof exports] && exports && !exports.nodeType)
        ? exports
        : undefined;
  
      /** Detect free variable `module`. */
      var freeModule = (objectTypes[typeof module] && module && !module.nodeType)
        ? module
        : undefined;
  
      /** Detect free variable `global` from Node.js. */
      var freeGlobal = checkGlobal(freeExports && freeModule && typeof global == 'object' && global);
  
      /** Detect free variable `self`. */
      var freeSelf = checkGlobal(objectTypes[typeof self] && self);
  
      /** Detect free variable `window`. */
      var freeWindow = checkGlobal(objectTypes[typeof window] && window);
  
      /** Detect `this` as the global object. */
      var thisGlobal = checkGlobal(objectTypes[typeof this] && this);
  
      /**
       * Used as a reference to the global object.
       *
       * The `this` value is used if it's the global object to avoid Greasemonkey's
       * restricted `window` object, otherwise the `window` object is used.
       */
      var root = freeGlobal ||
        ((freeWindow !== (thisGlobal && thisGlobal.window)) && freeWindow) ||
          freeSelf || thisGlobal || Function('return this')();
  
      /**
       * 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 {...*} args The arguments to invoke `func` with.
       * @returns {*} Returns the result of `func`.
       */
      function apply(func, thisArg, args) {
        var length = args.length;
        switch (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);
      }
  
      /**
       * Checks if `value` is a global object.
       *
       * @private
       * @param {*} value The value to check.
       * @returns {null|Object} Returns `value` if it's a global object, else `null`.
       */
      function checkGlobal(value) {
        return (value && value.Object === Object) ? value : null;
      }
  
      /**
       * 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;
      }
  
      /**
       * 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) {
        value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
        length = length == null ? MAX_SAFE_INTEGER : length;
        return value > -1 && value % 1 == 0 && value < length;
      }
  
      /**
       * 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;
      }
  
      /** Used for built-in method references. */
      var objectProto = Object.prototype;
  
      /**
       * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
       * of values.
       */
      var objectToString = objectProto.toString;
  
      /** Built-in value references. */
      var objectCreate = Object.create;
  
      /* Built-in method references for those with the same name as other `lodash` methods. */
      var nativeMax = Math.max,
          nativeMin = Math.min;
  
      /**
       * The base implementation of `_.create` without support for assigning
       * properties to the created object.
       *
       * @private
       * @param {Object} prototype The object to inherit from.
       * @returns {Object} Returns the new object.
       */
      function baseCreate(proto) {
        return isObject(proto) ? objectCreate(proto) : {};
      }
  
      /**
       * Creates an array that is the composition of partially applied arguments,
       * placeholders, and provided arguments into a single array of arguments.
       *
       * @private
       * @param {Array|Object} 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|Object} 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;
      }
  
      /**
       * 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 of wrapper flags. See `createWrapper` for more details.
       * @param {*} [thisArg] The `this` binding of `func`.
       * @returns {Function} Returns the new wrapped function.
       */
      function createBaseWrapper(func, bitmask, thisArg) {
        var isBind = bitmask & BIND_FLAG,
            Ctor = createCtorWrapper(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 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 createCtorWrapper(Ctor) {
        return function() {
          // Use a `switch` statement to work with class constructors.
          // See http://ecma-international.org/ecma-262/6.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 of wrapper flags. See `createWrapper` for more details.
       * @param {number} arity The arity of `func`.
       * @returns {Function} Returns the new wrapped function.
       */
      function createCurryWrapper(func, bitmask, arity) {
        var Ctor = createCtorWrapper(func);
  
        function wrapper() {
          var length = arguments.length,
              args = Array(length),
              index = length,
              placeholder = getPlaceholder(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 createRecurryWrapper(
              func, bitmask, createHybridWrapper, 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 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 of wrapper flags. See `createWrapper` 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 createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
        var isAry = bitmask & ARY_FLAG,
            isBind = bitmask & BIND_FLAG,
            isBindKey = bitmask & BIND_KEY_FLAG,
            isCurried = bitmask & (CURRY_FLAG | CURRY_RIGHT_FLAG),
            isFlip = bitmask & FLIP_FLAG,
            Ctor = isBindKey ? undefined : createCtorWrapper(func);
  
        function wrapper() {
          var length = arguments.length,
              index = length,
              args = Array(length);
  
          while (index--) {
            args[index] = arguments[index];
          }
          if (isCurried) {
            var placeholder = getPlaceholder(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 createRecurryWrapper(
              func, bitmask, createHybridWrapper, 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 || createCtorWrapper(fn);
          }
          return fn.apply(thisBinding, args);
        }
        return wrapper;
      }
  
      /**
       * Creates a function that wraps `func` to invoke it with the optional `this`
       * binding of `thisArg` and the `partials` prepended to those provided to
       * the wrapper.
       *
       * @private
       * @param {Function} func The function to wrap.
       * @param {number} bitmask The bitmask of wrapper flags. See `createWrapper` 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 createPartialWrapper(func, bitmask, thisArg, partials) {
        var isBind = bitmask & BIND_FLAG,
            Ctor = createCtorWrapper(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 function that wraps `func` to continue currying.
       *
       * @private
       * @param {Function} func The function to wrap.
       * @param {number} bitmask The bitmask of wrapper flags. See `createWrapper` 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 createRecurryWrapper(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
        var isCurry = bitmask & CURRY_FLAG,
            newArgPos = argPos ? copyArray(argPos) : undefined,
            newHolders = isCurry ? holders : undefined,
            newHoldersRight = isCurry ? undefined : holders,
            newPartials = isCurry ? partials : undefined,
            newPartialsRight = isCurry ? undefined : partials;
  
        bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
        bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
  
        if (!(bitmask & CURRY_BOUND_FLAG)) {
          bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
        }
  
        var result = wrapFunc(func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, newHoldersRight, newArgPos, ary, arity);
        result.placeholder = placeholder;
        return result;
      }
  
      /**
       * 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 of wrapper flags.
       *  The bitmask may be composed of the following 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`
       * @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 createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
        var isBindKey = bitmask & BIND_KEY_FLAG;
        if (!isBindKey && typeof func != 'function') {
          throw new TypeError(FUNC_ERROR_TEXT);
        }
        var length = partials ? partials.length : 0;
        if (!length) {
          bitmask &= ~(PARTIAL_FLAG | 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 & PARTIAL_RIGHT_FLAG) {
          var partialsRight = partials,
              holdersRight = holders;
  
          partials = holders = undefined;
        }
  
        var newData = [
          func, bitmask, thisArg, partials, holders, partialsRight, holdersRight,
          argPos, ary, arity
        ];
  
        func = newData[0];
        bitmask = newData[1];
        thisArg = newData[2];
        partials = newData[3];
        holders = newData[4];
        arity = newData[9] = newData[9] == null
          ? (isBindKey ? 0 : func.length)
          : nativeMax(newData[9] - length, 0);
  
        if (!arity && bitmask & (CURRY_FLAG | CURRY_RIGHT_FLAG)) {
          bitmask &= ~(CURRY_FLAG | CURRY_RIGHT_FLAG);
        }
        if (!bitmask || bitmask == BIND_FLAG) {
          var result = createBaseWrapper(func, bitmask, thisArg);
        } else if (bitmask == CURRY_FLAG || bitmask == CURRY_RIGHT_FLAG) {
          result = createCurryWrapper(func, bitmask, arity);
        } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !holders.length) {
          result = createPartialWrapper(func, bitmask, thisArg, partials);
        } else {
          result = createHybridWrapper.apply(undefined, newData);
        }
        return result;
      }
  
      /**
       * Gets the argument placeholder value for `func`.
       *
       * @private
       * @param {Function} func The function to inspect.
       * @returns {*} Returns the placeholder value.
       */
      function getPlaceholder(func) {
        var object = func;
        return object.placeholder;
      }
  
      /**
       * 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;
      }
  
      /**
       * Checks if `value` is classified as a `Function` object.
       *
       * @static
       * @memberOf _
       * @category Lang
       * @param {*} value The value to check.
       * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
       * @example
       *
       * _.isFunction(_);
       * // => true
       *
       * _.isFunction(/abc/);
       * // => false
       */
      function isFunction(value) {
        // The use of `Object#toString` avoids issues with the `typeof` operator
        // in Safari 8 which returns 'object' for typed array and weak map constructors,
        // and PhantomJS 1.9 which returns 'function' for `NodeList` instances.
        var tag = isObject(value) ? objectToString.call(value) : '';
        return tag == funcTag || tag == genTag;
      }
  
      /**
       * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
       * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
       *
       * @static
       * @memberOf _
       * @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 && (type == 'object' || type == 'function');
      }
  
      /**
       * Converts `value` to an integer.
       *
       * **Note:** This function is loosely based on [`ToInteger`](http://www.ecma-international.org/ecma-262/6.0/#sec-tointeger).
       *
       * @static
       * @memberOf _
       * @category Lang
       * @param {*} value The value to convert.
       * @returns {number} Returns the converted integer.
       * @example
       *
       * _.toInteger(3);
       * // => 3
       *
       * _.toInteger(Number.MIN_VALUE);
       * // => 0
       *
       * _.toInteger(Infinity);
       * // => 1.7976931348623157e+308
       *
       * _.toInteger('3');
       * // => 3
       */
      function toInteger(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;
        }
        var remainder = value % 1;
        return value === value ? (remainder ? value - remainder : value) : 0;
      }
  
      /**
       * Converts `value` to a number.
       *
       * @static
       * @memberOf _
       * @category Lang
       * @param {*} value The value to process.
       * @returns {number} Returns the number.
       * @example
       *
       * _.toNumber(3);
       * // => 3
       *
       * _.toNumber(Number.MIN_VALUE);
       * // => 5e-324
       *
       * _.toNumber(Infinity);
       * // => Infinity
       *
       * _.toNumber('3');
       * // => 3
       */
      function toNumber(value) {
        if (isObject(value)) {
          var other = isFunction(value.valueOf) ? value.valueOf() : value;
          value = isObject(other) ? (other + '') : other;
        }
        if (typeof value != 'string') {
          return value === 0 ? value : +value;
        }
        value = value.replace(reTrim, '');
        var isBinary = reIsBinary.test(value);
        return (isBinary || reIsOctal.test(value))
          ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
          : (reIsBadHex.test(value) ? NAN : +value);
      }
  
      _.curry = curry;
      _.curry.placeholder = _;
  };
  