/**
 * Debounce utility: limits the rate at which a function can be called.
 * @param {Function} func - The function to debounce.
 * @param {number} wait - The wait time in milliseconds.
 */
function debounce(func, wait) {
    let timeout;
    return function () {
        const context = this;
        const args = arguments;
        clearTimeout(timeout);
        timeout = setTimeout(() => {
            func.apply(context, args);
        }, wait);
    };
}

/**
 * Throttle utility: ensures a function is called no more than once every `delay` milliseconds.
 * @param {Function} func - The function to throttle.
 * @param {number} delay - The minimum time between function calls in milliseconds.
 */
function throttle(func, delay) {
    let lastCall = 0;
    let timeoutId = null;

    return function (...args) {
        const now = Date.now();

        if (now - lastCall >= delay) {
            func.apply(this, args);
            lastCall = now;
        } else {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(() => {
                func.apply(this, args);
                lastCall = Date.now();
            }, delay - (now - lastCall));
        }
    };
}