(function (global) {
    global['_'] = {};

    /**
     * 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) {
        let index = -1
        const length = source.length

        array || (array = new Array(length))
        while (++index < length) {
            array[index] = source[index]
        }
        return array
    }

    // A (possibly faster) way to get the current timestamp as an integer.
    _.now = Date.now || function () {
        return new Date().getTime();
    };

    _.throttle = function (func, wait, options) {
        var timeout, context, args, result;
        var previous = 0;
        if (!options) options = {};

        var later = function () {
            previous = options.leading === false ? 0 : _.now();
            timeout = null;
            result = func.apply(context, args);
            if (!timeout) context = args = null;
        };

        var throttled = function () {
            var now = _.now();
            if (!previous && options.leading === false) previous = now;
            var remaining = wait - (now - previous);
            context = this;
            args = arguments;
            if (remaining <= 0 || remaining > wait) {
                if (timeout) {
                    clearTimeout(timeout);
                    timeout = null;
                }
                previous = now;
                result = func.apply(context, args);
                if (!timeout) context = args = null;
            } else if (!timeout && options.trailing !== false) {
                timeout = setTimeout(later, remaining);
            }
            return result;
        };

        throttled.cancel = function () {
            clearTimeout(timeout);
            previous = 0;
            timeout = context = args = null;
        };

        return throttled;
    };

    _.shuffle  = function (array) {
        const length = array == null ? 0 : array.length
        if (!length) {
            return []
        }
        let index = -1
        const lastIndex = length - 1
        const result = copyArray(array)
        while (++index < length) {
            const rand = index + Math.floor(Math.random() * (lastIndex - index + 1))
            const value = result[rand]
            result[rand] = result[index]
            result[index] = value
        }
        return result
    }
})(window)