function promoCarousel (cycleSpeed, transitionSpeed, resumeSpeed) {

    // INITIALIZATION
    var promoCount = jQuery('#promo-carousel > li').length;

    // ATTACH NAV BUTTONS
    var nav = document.createElement('ul');
    nav.setAttribute('id', 'promo-carousel-nav');
    for (var i = 0; i < promoCount; i++) {
        var link = document.createElement('a');
        link.setAttribute('href', '#');
        link.onclick = (function (i) { return function () { instance.select(i); return false; } })(i);
        link.appendChild(document.createTextNode(i + 1));
        var li = document.createElement('li');
        li.appendChild(link);
        nav.appendChild(li);
    }
    var promo = document.getElementById('promo');
    promo.appendChild(nav);

    // MAKE FIRST PROMO ACTIVE
    jQuery('#promo-carousel > li:gt(0)').hide();
    jQuery('#promo-carousel-nav li:eq(0)').addClass('active');
    var activePromo = 0;

    // BEGIN ROTATION
    var timer = setTimeout(function () { instance.next(); }, cycleSpeed);

    // PRIVATE METHODS
    // jump to the specified promo, fading out current and fading in new promo over 'transitionSpeed' milliseconds
    function show (index) {
        if (index != activePromo) {
            // Highlight selected nav item
            jQuery('#promo-carousel-nav li.active').removeClass('active');
            jQuery('#promo-carousel-nav li:eq(' + index + ')').addClass('active');
            // Fade current promo and show new one
            jQuery('#promo-carousel > li:visible').fadeOut(parseInt(transitionSpeed / 2), function () {
                jQuery('#promo-carousel > li:eq(' + index + ')').fadeIn(parseInt(transitionSpeed / 2), function () {
                    activePromo = index;
                });
            });
        }
    }

    // PUBLIC METHODS
    var instance = {
        // jump to a specific promo and hold for 'resumeSpeed' milliseconds before resuming cycling
        select: function (index) {
            clearTimeout(timer);
            show(index);
            timer = setTimeout(instance.next, resumeSpeed);
            return this;
        },
        // cycle to next promo every 'cycleSpeed' milliseconds
        next: function () {
            show((activePromo + 1) % promoCount);
            timer = setTimeout(instance.next, cycleSpeed);
            return this;
        }
    }
    return instance;
};