(function () {

    var WidgetName;             // forward declaration
    YAHOO.widget.Carousel = function (el, cfg) {

        YAHOO.widget.Carousel.superclass.constructor.call(this, el, cfg);
    };

    var Carousel    = YAHOO.widget.Carousel,
        Dom         = YAHOO.util.Dom,
        Event       = YAHOO.util.Event,
        JS          = YAHOO.lang;

    WidgetName = "Carousel";

    var instances = {},

    afterScrollEvent = "afterScroll",
    allItemsRemovedEvent = "allItemsRemoved",
    beforeHideEvent = "beforeHide",
    beforePageChangeEvent = "beforePageChange",
    beforeScrollEvent = "beforeScroll",
    beforeShowEvent = "beforeShow",
    blurEvent = "blur",
    focusEvent = "focus",
    hideEvent = "hide",
    itemAddedEvent = "itemAdded",
    itemRemovedEvent = "itemRemoved",
    itemReplacedEvent = "itemReplaced",
    itemSelectedEvent = "itemSelected",
    loadItemsEvent = "loadItems",
    navigationStateChangeEvent = "navigationStateChange",
    pageChangeEvent = "pageChange",
    renderEvent = "render",
    showEvent = "show",
    startAutoPlayEvent = "startAutoPlay",
    stopAutoPlayEvent = "stopAutoPlay",
    uiUpdateEvent = "uiUpdate";

    function setStyles(el, styles) {
         var which;

         for (which in styles) {
             if (styles.hasOwnProperty(which)) {
                 Dom.setStyle(el, which, styles[which]);
             }
         }
     }

    function createElement(el, attrs) {
        var newEl = document.createElement(el);

        attrs = attrs || {};
        if (attrs.className) {
            Dom.addClass(newEl, attrs.className);
        }

        if (attrs.styles) {
            setStyles(newEl, attrs.styles);
        }

        if (attrs.parent) {
            attrs.parent.appendChild(newEl);
        }

        if (attrs.id) {
            newEl.setAttribute("id", attrs.id);
        }

        if (attrs.content) {
            if (attrs.content.nodeName) {
                newEl.appendChild(attrs.content);
            } else {
                newEl.innerHTML = attrs.content;
            }
        }

        return newEl;
    }

    function getStyle(el, style, type) {
        var value;

        if (!el) {
            return 0;
        }

        function getStyleIntVal(el, style) {
            var val;

            if (style == "marginRight" && YAHOO.env.ua.webkit) {
                val = parseInt(Dom.getStyle(el, "marginLeft"), 10);
            } else {
                val = parseInt(Dom.getStyle(el, style), 10);
            }

            return JS.isNumber(val) ? val : 0;
        }

        function getStyleFloatVal(el, style) {
            var val;

            if (style == "marginRight" && YAHOO.env.ua.webkit) {
                val = parseFloat(Dom.getStyle(el, "marginLeft"));
            } else {
                val = parseFloat(Dom.getStyle(el, style));
            }

            return JS.isNumber(val) ? val : 0;
        }

        if (typeof type == "undefined") {
            type = "int";
        }

        switch (style) {
        case "height":
            value = el.offsetHeight;
            if (value > 0) {
                value += getStyleIntVal(el, "marginTop")        +
                        getStyleIntVal(el, "marginBottom");
            } else {
                value = getStyleFloatVal(el, "height")          +
                        getStyleIntVal(el, "marginTop")         +
                        getStyleIntVal(el, "marginBottom")      +
                        getStyleIntVal(el, "borderTopWidth")    +
                        getStyleIntVal(el, "borderBottomWidth") +
                        getStyleIntVal(el, "paddingTop")        +
                        getStyleIntVal(el, "paddingBottom");
            }
            break;
        case "width":
            value = el.offsetWidth;
            if (value > 0) {
                value += getStyleIntVal(el, "marginLeft")       +
                        getStyleIntVal(el, "marginRight");
            } else {
                value = getStyleFloatVal(el, "width")           +
                        getStyleIntVal(el, "marginLeft")        +
                        getStyleIntVal(el, "marginRight")       +
                        getStyleIntVal(el, "borderLeftWidth")   +
                        getStyleIntVal(el, "borderRightWidth")  +
                        getStyleIntVal(el, "paddingLeft")       +
                        getStyleIntVal(el, "paddingRight");
            }
            break;
        default:
            if (type == "int") {
                value = getStyleIntVal(el, style);
            } else if (type == "float") {
                value = getStyleFloatVal(el, style);
            } else {
                value = Dom.getStyle(el, style);
            }
            break;
        }

        return value;
    }

    function getCarouselItemSize(which) {
        var carousel = this,
            child,
            item,
            size     = 0,
            first = carousel.get("firstVisible"),
            vertical = false;

        if (carousel._itemsTable.numItems === 0) {
            return 0;
        }

        item = carousel._itemsTable.items[first] ||
               carousel._itemsTable.loading[first];

        if (JS.isUndefined(item)) {
            return 0;
        }

        child = Dom.get(item.id);

        if (typeof which == "undefined") {
            vertical = carousel.get("isVertical");
        } else {
            vertical = which == "height";
        }

        if (this._itemAttrCache[which]) {
            return this._itemAttrCache[which];
        }

        if (vertical) {
            size = getStyle(child, "height");
        } else {
            size = getStyle(child, "width");
        }

        this._itemAttrCache[which] = size;

        return size;
    }

    function getRevealSize() {
        var carousel = this, isVertical, sz;

        isVertical = carousel.get("isVertical");
        sz  = getCarouselItemSize.call(carousel,
                isVertical ? "height" : "width");
        return (sz * carousel.get("revealAmount") / 100);
    }

    function getCarouselItemPosition(pos) {
        var carousel    = this,
            itemsPerRow = carousel._cols,
            itemsPerCol = carousel._rows,
            page,
            sz,
            isVertical,
            itemsCol,
            itemsRow,
            sentinel,
            delta = 0,
            top,
            left,
            rsz,
            styles = {},
            index = 0,
            itemsTable = carousel._itemsTable,
            items = itemsTable.items,
            loading = itemsTable.loading;

        isVertical = carousel.get("isVertical");
        isFading = carousel.get("isFading");
        sz  = getCarouselItemSize.call(carousel,
                isVertical ? "height" : "width");
        rsz = getRevealSize.call(carousel);

        // adjust for items not yet loaded
        while (index < pos) {
            if (!items[index] && !loading[index]) {
                delta++;
            }
            index++;
        }
        pos -= delta;

        if (itemsPerCol) {
            page = this.getPageForItem(pos);
            if (isVertical) {
                itemsRow = Math.floor(pos/itemsPerRow);
                delta = itemsRow;
                top = delta * sz;
                styles.top  = (top + rsz) + "px";

                sz  = getCarouselItemSize.call(carousel, "width");

                itemsCol = pos % itemsPerRow;
                delta = itemsCol;
                left = delta * sz;
                styles.left = left + "px";
            } else {
                itemsCol = pos % itemsPerRow;
                sentinel = (page - 1) * itemsPerRow;
                delta = itemsCol + sentinel;
                left = delta * sz;
                styles.left = (left + rsz) + "px";

                sz  = getCarouselItemSize.call(carousel, "height");

                itemsRow = Math.floor(pos/itemsPerRow);
                sentinel = (page - 1) * itemsPerCol;
                delta = itemsRow - sentinel;
                top = delta * sz;

                styles.top  = top + "px";
            }
        } else {
	        if (isVertical) {
	            styles.left = 0;
	            styles.top  = ((pos * sz) + rsz) + "px";
	        } else if ( isFading ) {
	        	styles.opacity = 0;
	        } else {
	            styles.top  = 0;
	            styles.left = ((pos * sz) + rsz) + "px";
	        }
        }

        return styles;
    }

    function getFirstVisibleForPosition(pos) {
        var num = this.get("numVisible");
        return Math.floor(pos / num) * num;
    }

    function getScrollOffset(delta) {
        var itemSize = 0,
            size     = 0;

        itemSize = getCarouselItemSize.call(this);
        size = itemSize * delta;

        return size;
    }

    function scrollPageBackward(ev, obj) {
        obj.scrollPageBackward();
        Event.preventDefault(ev);
    }

    function scrollPageForward(ev, obj) {
        obj.scrollPageForward();
        Event.preventDefault(ev);
    }

     function setItemSelection(newpos, oldpos) {
        var carousel = this,
            cssClass   = carousel.CLASSES,
            el,
            firstItem  = carousel._firstItem,
            isCircular = carousel.get("isCircular"),
            numItems   = carousel.get("numItems"),
            numVisible = carousel.get("numVisible"),
            position   = oldpos,
            sentinel   = firstItem + numVisible - 1;

        if (position >= 0 && position < numItems) {
            if (!JS.isUndefined(carousel._itemsTable.items[position])) {
                el = Dom.get(carousel._itemsTable.items[position].id);
                if (el) {
                    Dom.removeClass(el, cssClass.SELECTED_ITEM);
                }
            }
        }

        if (JS.isNumber(newpos)) {
            newpos = parseInt(newpos, 10);
            newpos = JS.isNumber(newpos) ? newpos : 0;
        } else {
            newpos = firstItem;
        }

        if (JS.isUndefined(carousel._itemsTable.items[newpos])) {
            newpos = getFirstVisibleForPosition.call(carousel, newpos);
            carousel.scrollTo(newpos); // still loading the item
        }

        if (!JS.isUndefined(carousel._itemsTable.items[newpos])) {
            el = Dom.get(carousel._itemsTable.items[newpos].id);
            if (el) {
                Dom.addClass(el, cssClass.SELECTED_ITEM);
            }
        }

        if (newpos < firstItem || newpos > sentinel) { // out of focus
            newpos = getFirstVisibleForPosition.call(carousel, newpos);
            carousel.scrollTo(newpos);
        }
    }

    function syncNavigation() {
        var attach   = false,
            carousel = this,
            cssClass = carousel.CLASSES,
            i,
            navigation,
            sentinel;

        // Don't do anything if the Carousel is not rendered
        if (!carousel._hasRendered) {
            return;
        }

        navigation = carousel.get("navigation");
        sentinel   = carousel._firstItem + carousel.get("numVisible");

        if (navigation.prev) {
            if (carousel.get("numItems") === 0 || carousel._firstItem === 0) {
                if (carousel.get("numItems") === 0 ||
                   !carousel.get("isCircular")) {
                    Event.removeListener(navigation.prev, "click",
                            scrollPageBackward);
                    Dom.addClass(navigation.prev, cssClass.FIRST_NAV_DISABLED);
                    for (i = 0; i < carousel._navBtns.prev.length; i++) {
                        carousel._navBtns.prev[i].setAttribute("disabled",
                                "true");
                    }
                    carousel._prevEnabled = false;
                } else {
                    attach = !carousel._prevEnabled;
                }
            } else {
                attach = !carousel._prevEnabled;
            }

            if (attach) {
                Event.on(navigation.prev, "click", scrollPageBackward,
                         carousel);
                Dom.removeClass(navigation.prev, cssClass.FIRST_NAV_DISABLED);
                for (i = 0; i < carousel._navBtns.prev.length; i++) {
                    carousel._navBtns.prev[i].removeAttribute("disabled");
                }
                carousel._prevEnabled = true;
            }
        }

        attach = false;
        if (navigation.next) {
            if (sentinel >= carousel.get("numItems")) {
                if (!carousel.get("isCircular")) {
                    Event.removeListener(navigation.next, "click",
                            scrollPageForward);
                    Dom.addClass(navigation.next, cssClass.DISABLED);
                    for (i = 0; i < carousel._navBtns.next.length; i++) {
                        carousel._navBtns.next[i].setAttribute("disabled",
                                "true");
                    }
                    carousel._nextEnabled = false;
                } else {
                    attach = !carousel._nextEnabled;
                }
            } else {
                attach = !carousel._nextEnabled;
            }

            if (attach) {
                Event.on(navigation.next, "click", scrollPageForward,
                         carousel);
                Dom.removeClass(navigation.next, cssClass.DISABLED);
                for (i = 0; i < carousel._navBtns.next.length; i++) {
                    carousel._navBtns.next[i].removeAttribute("disabled");
                }
                carousel._nextEnabled = true;
            }
        }

        carousel.fireEvent(navigationStateChangeEvent,
                { next: carousel._nextEnabled, prev: carousel._prevEnabled });
    }

    function syncPagerUi(page) {
        var carousel = this, numPages, numVisible;

        // Don't do anything if the Carousel is not rendered
        if (!carousel._hasRendered) {
            return;
        }

        numVisible = carousel.get("numVisible");

        if (!JS.isNumber(page)) {
            page = Math.floor(carousel.get("selectedItem") / numVisible);
        }

        numPages = Math.ceil(carousel.get("numItems") / numVisible);

        carousel._pages.num = numPages;
        carousel._pages.cur = page;

        if (numPages > carousel.CONFIG.MAX_PAGER_BUTTONS) {
            carousel._updatePagerMenu();
        } else {
            carousel._updatePagerButtons();
        }
    }

    function getDimensions(el, which) {
        switch (which) {
        case 'height':
            return  getStyle(el, "marginTop")        +
                    getStyle(el, "marginBottom")     +
                    getStyle(el, "paddingTop")       +
                    getStyle(el, "paddingBottom")    +
                    getStyle(el, "borderTopWidth")   +
                    getStyle(el, "borderBottomWidth");
        case 'width':
            return   getStyle(el, "marginLeft")      +
                     getStyle(el, "marginRight")     +
                     getStyle(el, "paddingLeft")     +
                     getStyle(el, "paddingRight")    +
                     getStyle(el, "borderLeftWidth") +
                     getStyle(el, "borderRightWidth");
        default:
            break;
        }

        return getStyle(el, which);
    }

    function syncUi(o) {
        var carousel = this;

        if (!JS.isObject(o)) {
            return;
        }

        switch (o.ev) {
        case itemAddedEvent:
            carousel._syncUiForItemAdd(o);
            break;
        case itemRemovedEvent:
            carousel._syncUiForItemRemove(o);
            break;
        case itemReplacedEvent:
            carousel._syncUiForItemReplace(o);
            break;
        case loadItemsEvent:
            carousel._syncUiForLazyLoading(o);
            break;
        }

        carousel.fireEvent(uiUpdateEvent);
    }

    function updateStateAfterScroll(item, sentinel) {
        var carousel   = this,
            page       = carousel.get("currentPage"),
            newPage,
            numPerPage = carousel.get("numVisible");

        newPage = parseInt(carousel._firstItem / numPerPage, 10);
        if (newPage != page) {
            carousel.setAttributeConfig("currentPage", { value: newPage });
            carousel.fireEvent(pageChangeEvent, newPage);
        }

        if (carousel.get("selectOnScroll")) {
            if (carousel.get("selectedItem") != carousel._selectedItem) {
                carousel.set("selectedItem", carousel._selectedItem);
            }
        }

        clearTimeout(carousel._autoPlayTimer);
        delete carousel._autoPlayTimer;
        if (carousel.isAutoPlayOn()) {
            carousel.startAutoPlay();
        }

        carousel.fireEvent(afterScrollEvent,
                           { first: carousel._firstItem,
                             last: sentinel },
                           carousel);
    }

    Carousel.getById = function (id) {
        return instances[id] ? instances[id].object : false;
    };

    YAHOO.extend(Carousel, YAHOO.util.Element, {

        _rows: null,

        _cols: null,

        _animObj: null,

        _carouselEl: null,

        _clipEl: null,

        _firstItem: 0,

        _hasFocus: false,

        _hasRendered: false,

        _isAnimationInProgress: false,

        _isAutoPlayInProgress: false,

        _itemsTable: null,

        _navBtns: null,

        _navEl: null,

        _nextEnabled: true,

        _pages: null,

        _pagination: {},

        _prevEnabled: true,

        _recomputeSize: true,

         _itemAttrCache: {},

        CLASSES: {
            BUTTON: "yui-carousel-button",
            CAROUSEL: "yui-carousel",
            CAROUSEL_EL: "yui-carousel-element",
            CONTAINER: "yui-carousel-container",
            CONTENT: "yui-carousel-content",
            DISABLED: "yui-carousel-button-disabled",
            FIRST_NAV: " yui-carousel-first-button",
            FIRST_NAV_DISABLED: "yui-carousel-first-button-disabled",
            FIRST_PAGE: "yui-carousel-nav-first-page",
            FOCUSSED_BUTTON: "yui-carousel-button-focus",
            HORIZONTAL: "yui-carousel-horizontal",
            ITEM_LOADING: "yui-carousel-item-loading",
            MIN_WIDTH: "yui-carousel-min-width",
            NAVIGATION: "yui-carousel-nav",
            NEXT_NAV: " yui-carousel-next-button",
            NEXT_PAGE: "yui-carousel-next",
            NAV_CONTAINER: "yui-carousel-buttons",
            PAGER_ITEM: "yui-carousel-pager-item",
            PAGINATION: "yui-carousel-pagination",
            PAGE_FOCUS: "yui-carousel-nav-page-focus",
            PREV_PAGE: "yui-carousel-prev",
            SELECTED_ITEM: "yui-carousel-item-selected",
            SELECTED_NAV: "yui-carousel-nav-page-selected",
            VERTICAL: "yui-carousel-vertical",
            MULTI_ROW: "yui-carousel-multi-row",
            ROW: "yui-carousel-row",
            VERTICAL_CONTAINER: "yui-carousel-vertical-container",
            VISIBLE: "yui-carousel-visible"

        },

        CONFIG: {
            FIRST_VISIBLE: 0,
            HORZ_MIN_WIDTH: 180,
            MAX_PAGER_BUTTONS: 25,
            VERT_MIN_WIDTH: 115,
            NUM_VISIBLE: 3
        },

        STRINGS: {
            ITEM_LOADING_CONTENT: "Loading",
            NEXT_BUTTON_TEXT: "Next Page",
            PAGER_PREFIX_TEXT: "Go to page ",
            PREVIOUS_BUTTON_TEXT: "Previous Page"
        },
        addItem: function (item, index) {
            var carousel = this,
                className,
                content,
                elId,
                replaceItems = 0,
                newIndex, // Add newIndex as workaround for undefined pos
                numItems = carousel.get("numItems");

            if (!item) {
                return false;
            }

            if (JS.isString(item) || item.nodeName) {
                content = item.nodeName ? item.innerHTML : item;
            } else if (JS.isObject(item)) {
                content = item.content;
            } else {
                return false;
            }

            className = item.className || "";
            elId      = item.id ? item.id : Dom.generateId();

            if (JS.isUndefined(index)) {
                carousel._itemsTable.items.push({
                        item      : content,
                        className : className,
                        id        : elId
                });
                // Add newIndex as workaround for undefined pos
                newIndex = carousel._itemsTable.items.length-1;
            } else {
                if (index < 0 || index > numItems) {
                    return false;
                }

                // make sure we splice into the correct position
                if(!carousel._itemsTable.items[index]){
                    carousel._itemsTable.items[index] = undefined;
                    replaceItems = 1;
                }

                carousel._itemsTable.items.splice(index, replaceItems, {
                        item      : content,
                        className : className,
                        id        : elId
                });
            }
            carousel._itemsTable.numItems++;

            if (numItems < carousel._itemsTable.items.length) {
                carousel.set("numItems", carousel._itemsTable.items.length);
            }

            // Add newPos as workaround for undefined pos
            carousel.fireEvent(itemAddedEvent, { pos: index, ev: itemAddedEvent, newPos:newIndex });

            return true;
        },

        addItems: function (items) {
            var i, n, rv = true;

            if (!JS.isArray(items)) {
                return false;
            }

            for (i = 0, n = items.length; i < n; i++) {
                if (this.addItem(items[i][0], items[i][1]) === false) {
                    rv = false;
                }
            }

            return rv;
        },

        /**
         * Remove focus from the Carousel.
         *
         * @method blur
         * @public
         */
        blur: function () {
            this._carouselEl.blur();
            this.fireEvent(blurEvent);
        },

        /**
         * Clears the items from Carousel.
         *
         * @method clearItems
         * @public
         */
        clearItems: function () {
            var carousel = this, n = carousel.get("numItems");

            while (n > 0) {
                if (!carousel.removeItem(0)) {
                }
                /*
                    For dynamic loading, the numItems may be much larger than
                    the actual number of items in the table. So, set the
                    numItems to zero, and break out of the loop if the table
                    is already empty.
                 */
                if (carousel._itemsTable.numItems === 0) {
                    carousel.set("numItems", 0);
                    break;
                }
                n--;
            }

            carousel.fireEvent(allItemsRemovedEvent);
        },

        /**
         * Set focus on the Carousel.
         *
         * @method focus
         * @public
         */
        focus: function () {
            var carousel = this,
                first,
                focusEl,
                isSelectionInvisible,
                itemsTable,
                last,
                numVisible,
                selectOnScroll,
                selected,
                selItem;

            // Don't do anything if the Carousel is not rendered
            if (!carousel._hasRendered) {
                return;
            }

            if (carousel.isAnimating()) {
                // this messes up real bad!
                return;
            }

            selItem              = carousel.get("selectedItem");
            numVisible           = carousel.get("numVisible");
            selectOnScroll       = carousel.get("selectOnScroll");
            selected             = (selItem >= 0) ?
                                   carousel.getItem(selItem) : null;
            first                = carousel.get("firstVisible");
            last                 = first + numVisible - 1;
            isSelectionInvisible = (selItem < first || selItem > last);
            focusEl              = (selected && selected.id) ?
                                   Dom.get(selected.id) : null;
            itemsTable           = carousel._itemsTable;

            if (!selectOnScroll && isSelectionInvisible) {
                focusEl = (itemsTable && itemsTable.items &&
                           itemsTable.items[first]) ?
                        Dom.get(itemsTable.items[first].id) : null;
            }

            if (focusEl) {
                try {
                    focusEl.focus();
                } catch (ex) {
                    // ignore focus errors
                }
            }

            carousel.fireEvent(focusEvent);
        },

        hide: function () {
            var carousel = this;

            if (carousel.fireEvent(beforeHideEvent) !== false) {
                carousel.removeClass(carousel.CLASSES.VISIBLE);
                carousel.fireEvent(hideEvent);
            }
        },

        init: function (el, attrs) {
            var carousel = this,
                elId     = el,  // save for a rainy day
                parse    = false,
                selected;

            if (!el) {
                return;
            }

            carousel._hasRendered = false;
            carousel._navBtns     = { prev: [], next: [] };
            carousel._pages       = { el: null, num: 0, cur: 0 };
            carousel._pagination  = {};
            carousel._itemAttrCache = {};

            carousel._itemsTable  = { loading: {}, numItems: 0,
                                      items: [], size: 0 };


            if (JS.isString(el)) {
                el = Dom.get(el);
            } else if (!el.nodeName) {
                return;
            }

            Carousel.superclass.init.call(carousel, el, attrs);

            // check if we're starting somewhere in the middle
            selected = carousel.get("selectedItem");
            if(selected > 0){
                carousel.set("firstVisible",getFirstVisibleForPosition.call(carousel,selected));
            }

            if (el) {
                if (!el.id) {   // in case the HTML element is passed
                    el.setAttribute("id", Dom.generateId());
                }
                parse = carousel._parseCarousel(el);
                if (!parse) {
                    carousel._createCarousel(elId);
                }
            } else {
                el = carousel._createCarousel(elId);
            }
            elId = el.id;

            carousel.initEvents();

            if (parse) {
                carousel._parseCarouselItems();
            }

            // add the selected class
            if(selected > 0){
                setItemSelection.call(carousel,selected,0);
            }

            if (!attrs || typeof attrs.isVertical == "undefined") {
                carousel.set("isVertical", false);
            }

            carousel._parseCarouselNavigation(el);
            carousel._navEl = carousel._setupCarouselNavigation();

            instances[elId] = { object: carousel };
            carousel._loadItems(Math.min(carousel.get("firstVisible")+carousel.get("numVisible"),carousel.get("numItems"))-1);
        },


        initAttributes: function (attrs) {
            var carousel = this;

            attrs = attrs || {};
            Carousel.superclass.initAttributes.call(carousel, attrs);

            carousel.setAttributeConfig("carouselEl", {
                    validator : JS.isString,
                    value     : attrs.carouselEl || "OL"
            });

            carousel.setAttributeConfig("carouselItemEl", {
                    validator : JS.isString,
                    value     : attrs.carouselItemEl || "LI"
            });

            carousel.setAttributeConfig("currentPage", {
                    readOnly : true,
                    value    : 0
            });

            carousel.setAttributeConfig("firstVisible", {
                    method    : carousel._setFirstVisible,
                    validator : carousel._validateFirstVisible,
                    value     :
                        attrs.firstVisible || carousel.CONFIG.FIRST_VISIBLE
            });

            carousel.setAttributeConfig("selectOnScroll", {
                    validator : JS.isBoolean,
                    value     : attrs.selectOnScroll || true
            });

            carousel.setAttributeConfig("numVisible", {
                    setter    : carousel._numVisibleSetter,
                    method    : carousel._setNumVisible,
                    validator : carousel._validateNumVisible,
                    value     : attrs.numVisible || carousel.CONFIG.NUM_VISIBLE
            });

            carousel.setAttributeConfig("numItems", {
                    method    : carousel._setNumItems,
                    validator : carousel._validateNumItems,
                    value     : carousel._itemsTable.numItems
            });

            carousel.setAttributeConfig("scrollIncrement", {
                    validator : carousel._validateScrollIncrement,
                    value     : attrs.scrollIncrement || 1
            });

            carousel.setAttributeConfig("selectedItem", {
                    setter    : carousel._selectedItemSetter,
                    method    : carousel._setSelectedItem,
                    validator : JS.isNumber,
                    value     : -1
            });

            carousel.setAttributeConfig("revealAmount", {
                    method    : carousel._setRevealAmount,
                    validator : carousel._validateRevealAmount,
                    value     : attrs.revealAmount || 0
            });

            carousel.setAttributeConfig("isCircular", {
                    validator : JS.isBoolean,
                    value     : attrs.isCircular || false
            });

            carousel.setAttributeConfig("isVertical", {
                    method    : carousel._setOrientation,
                    validator : JS.isBoolean,
                    value     : attrs.isVertical || false
            });

            carousel.setAttributeConfig("isFading", {
                    method    : carousel._setOrientation,
                    validator : JS.isBoolean,
                    value     : attrs.isFading || false
            });

            carousel.setAttributeConfig("navigation", {
                    method    : carousel._setNavigation,
                    validator : carousel._validateNavigation,
                    value     :
                        attrs.navigation || {prev: null,next: null,page: null}
            });

            carousel.setAttributeConfig("animation", {
                    validator : carousel._validateAnimation,
                    value     : attrs.animation || { speed: 0, effect: null }
            });

            carousel.setAttributeConfig("autoPlay", {
                    validator : JS.isNumber,
                    value     : attrs.autoPlay || 0
            });

            carousel.setAttributeConfig("autoPlayInterval", {
                    validator : JS.isNumber,
                    value     : attrs.autoPlayInterval || 0
            });

            carousel.setAttributeConfig("numPages", {
                    readOnly  : true,
                    getter    : carousel._getNumPages
            });

            carousel.setAttributeConfig("lastVisible", {
                    readOnly  : true,
                    getter    : carousel._getLastVisible
            });
        },

        initEvents: function () {
            var carousel = this,
                cssClass = carousel.CLASSES,
                focussedLi;

            carousel.on("keydown", carousel._keyboardEventHandler);

            carousel.on(afterScrollEvent, syncNavigation);

            carousel.on(itemAddedEvent, syncUi);

            carousel.on(itemRemovedEvent, syncUi);

            carousel.on(itemReplacedEvent, syncUi);

            carousel.on(itemSelectedEvent, function () {
                if (carousel._hasFocus) {
                    carousel.focus();
                }
            });

            carousel.on(loadItemsEvent, syncUi);

            carousel.on(allItemsRemovedEvent, function (ev) {
                carousel.scrollTo(0);
                syncNavigation.call(carousel);
                syncPagerUi.call(carousel);
            });

            carousel.on(pageChangeEvent, syncPagerUi, carousel);

            carousel.on(renderEvent, function (ev) {
                if (carousel.get("selectedItem") === null ||
                    carousel.get("selectedItem") <= 0) { //in either case
                carousel.set("selectedItem", carousel.get("firstVisible"));
                }
                syncNavigation.call(carousel, ev);
                syncPagerUi.call(carousel, ev);
                carousel._setClipContainerSize();
                carousel.show();
            });

            carousel.on("selectedItemChange", function (ev) {
                setItemSelection.call(carousel, ev.newValue, ev.prevValue);
                if (ev.newValue >= 0) {
                    carousel._updateTabIndex(
                            carousel.getElementForItem(ev.newValue));
                }
                carousel.fireEvent(itemSelectedEvent, ev.newValue);
            });

            carousel.on(uiUpdateEvent, function (ev) {
                syncNavigation.call(carousel, ev);
                syncPagerUi.call(carousel, ev);
            });

            carousel.on("firstVisibleChange", function (ev) {
                if (!carousel.get("selectOnScroll")) {
                    if (ev.newValue >= 0) {
                        carousel._updateTabIndex(
                                carousel.getElementForItem(ev.newValue));
                    }
                }
            });

            // Handle item selection on mouse click
            carousel.on("click", function (ev) {
                if (carousel.isAutoPlayOn()) {
                    carousel.stopAutoPlay();
                }
                carousel._itemClickHandler(ev);
                carousel._pagerClickHandler(ev);
            });

            // Restore the focus on the navigation buttons

            Event.onFocus(carousel.get("element"), function (ev, obj) {
                var target = Event.getTarget(ev);

                if (target && target.nodeName.toUpperCase() == "A" &&
                    Dom.getAncestorByClassName(target, cssClass.NAVIGATION)) {
                    if (focussedLi) {
                        Dom.removeClass(focussedLi, cssClass.PAGE_FOCUS);
                    }
                    focussedLi = target.parentNode;
                    Dom.addClass(focussedLi, cssClass.PAGE_FOCUS);
                } else {
                    if (focussedLi) {
                        Dom.removeClass(focussedLi, cssClass.PAGE_FOCUS);
                    }
                }

                obj._hasFocus = true;
                obj._updateNavButtons(Event.getTarget(ev), true);
            }, carousel);

            Event.onBlur(carousel.get("element"), function (ev, obj) {
                obj._hasFocus = false;
                obj._updateNavButtons(Event.getTarget(ev), false);
            }, carousel);
        },

        isAnimating: function () {
            return this._isAnimationInProgress;
        },

        isAutoPlayOn: function () {
            return this._isAutoPlayInProgress;
        },

        getElementForItem: function (index) {
            var carousel = this;

            if (index < 0 || index >= carousel.get("numItems")) {
                return null;
            }

            if (carousel._itemsTable.items[index]) {
                return Dom.get(carousel._itemsTable.items[index].id);
            }

            return null;
        },

        getElementForItems: function () {
            var carousel = this, els = [], i;

            for (i = 0; i < carousel._itemsTable.numItems; i++) {
                els.push(carousel.getElementForItem(i));
            }

            return els;
        },

        getItem: function (index) {
            var carousel = this;

            if (index < 0 || index >= carousel.get("numItems")) {
                return null;
            }

            if (carousel._itemsTable.numItems > index) {
                if (!JS.isUndefined(carousel._itemsTable.items[index])) {
                    return carousel._itemsTable.items[index];
                }
            }

            return null;
        },

        getItems: function () {
            return this._itemsTable.items;
        },

        getLoadingItems: function () {
            return this._itemsTable.loading;
        },

        getRows: function () {
            return this._rows;
        },

        getCols: function () {
            return this._cols;
        },

        getItemPositionById: function (id) {
            var carousel = this,
                n = carousel.get("numItems"),
                i = 0,
                items = carousel._itemsTable.items,
                item;

            while (i < n) {
                item = items[i] || {};
                if(item.id == id) {
                    return i;
                }
                i++;
            }

            return -1;
        },

        getVisibleItems: function () {
            var carousel = this,
                i        = carousel.get("firstVisible"),
                n        = i + carousel.get("numVisible"),
                r        = [];

            while (i < n) {
                r.push(carousel.getElementForItem(i));
                i++;
            }

            return r;
        },

        removeItem: function (index) {
            var carousel = this,
                item,
                num      = carousel.get("numItems");

            if (index < 0 || index >= num) {
                return false;
            }

            item = carousel._itemsTable.items.splice(index, 1);
            if (item && item.length == 1) {
                carousel._itemsTable.numItems--;
                carousel.set("numItems", num - 1);

                carousel.fireEvent(itemRemovedEvent,
                        { item: item[0], pos: index, ev: itemRemovedEvent });
                return true;
            }

            return false;
        },

        replaceItem: function (item, index) {
            var carousel = this,
                className,
                content,
                elId,
                numItems = carousel.get("numItems"),
                oel,
                el = item;

            if (!item) {
                return false;
            }

            if (JS.isString(item) || item.nodeName) {
                content = item.nodeName ? item.innerHTML : item;
            } else if (JS.isObject(item)) {
                content = item.content;
            } else {
                return false;
            }

            if (JS.isUndefined(index)) {
                return false;
            } else {
                if (index < 0 || index >= numItems) {
                    return false;
                }

                oel = carousel._itemsTable.items[index];
                if(!oel){
                    oel = carousel._itemsTable.loading[index];
                    carousel._itemsTable.items[index] = undefined;
                }

                carousel._itemsTable.items.splice(index, 1, {
                    item      : content,
                    className : item.className || "",
                    id        : Dom.generateId()
                });

                el = carousel._itemsTable.items[index];
            }
            carousel.fireEvent(itemReplacedEvent,
                    { newItem: el, oldItem: oel, pos: index, ev: itemReplacedEvent });

            return true;
        },

         replaceItems: function (items) {
             var i, n, rv = true;

             if (!JS.isArray(items)) {
                 return false;
             }

             for (i = 0, n = items.length; i < n; i++) {
                 if (this.replaceItem(items[i][0], items[i][1]) === false) {
                     rv = false;
                 }
             }

             return rv;
         },

        render: function (appendTo) {
            var carousel  = this,
                cssClass  = carousel.CLASSES,
                rows = carousel._rows;

            carousel.addClass(cssClass.CAROUSEL);

            if (!carousel._clipEl) {
                carousel._clipEl = carousel._createCarouselClip();
                carousel._clipEl.appendChild(carousel._carouselEl);
            }

            if (appendTo) {
                carousel.appendChild(carousel._clipEl);
                carousel.appendTo(appendTo);
            } else {
                if (!Dom.inDocument(carousel.get("element"))) {
                    return false;
                }
                carousel.appendChild(carousel._clipEl);
            }

            if (rows) {
                Dom.addClass(carousel._clipEl, cssClass.MULTI_ROW);
            }

            if (carousel.get("isVertical")) {
                carousel.addClass(cssClass.VERTICAL);
            } else {
                carousel.addClass(cssClass.HORIZONTAL);
            }

            if (carousel.get("numItems") < 1) {
                return false;
            }

            carousel._refreshUi();

            return true;
        },

        scrollBackward: function () {
            var carousel = this;
            carousel.scrollTo(carousel._firstItem -
                              carousel.get("scrollIncrement"));
        },

        scrollForward: function () {
            var carousel = this;
            carousel.scrollTo(carousel._firstItem +
                              carousel.get("scrollIncrement"));
        },

        scrollPageBackward: function () {
            var carousel = this,
                isVertical = carousel.get("isVertical"),
                cols       = carousel._cols,
                item     = carousel._firstItem - carousel.get("numVisible");

            if (item < 0) { // only account for multi-row when scrolling backwards from item 0
                if (cols) {
                    item = carousel._firstItem - cols;
                }
            }

            if (carousel.get("selectOnScroll")) {
                carousel._selectedItem = carousel._getSelectedItem(item);
            }

            carousel.scrollTo(item);
        },

        scrollPageForward: function () {
            var carousel = this,
                item     = carousel._firstItem + carousel.get("numVisible");

            if (item > carousel.get("numItems")) {
                item = 0;
            }

            if (carousel.get("selectOnScroll")) {
                carousel._selectedItem = carousel._getSelectedItem(item);
            }

            carousel.scrollTo(item);
        },

        scrollTo: function (item, dontSelect) {
            var carousel   = this, animate, animCfg, isCircular, isVertical,
                rows, delta, direction, firstItem, lastItem, itemsPerRow,
                itemsPerCol, numItems, numPerPage, offset, page, rv, sentinel,
                index, stopAutoScroll,
                itemsTable = carousel._itemsTable,
                items = itemsTable.items,
                loading = itemsTable.loading;

            if (JS.isUndefined(item) || item == carousel._firstItem ||
                carousel.isAnimating()) {
                return; // nothing to do!
            }

            animCfg        = carousel.get("animation");
            isCircular     = carousel.get("isCircular");
            isVertical     = carousel.get("isVertical");
            itemsPerRow    = carousel._cols;
            itemsPerCol    = carousel._rows;
            firstItem      = carousel._firstItem;
            numItems       = carousel.get("numItems");
            numPerPage     = carousel.get("numVisible");
            page           = carousel.get("currentPage");

            stopAutoScroll = function () {
                if (carousel.isAutoPlayOn()) {
                    carousel.stopAutoPlay();
                }
            };

            if (item < 0) {
                if (isCircular) {
                    item = numItems + item;
                } else {
                    stopAutoScroll.call(carousel);
                    return;
                }
            } else if (numItems > 0 && item > numItems - 1) {

                if (carousel.get("isCircular")) {
                    item = numItems - item;
                } else {
                    stopAutoScroll.call(carousel);
                    return;
                }
            }

            if (isNaN(item)) {
                return;
            }

            direction = (carousel._firstItem > item) ? "backward" : "forward";

            sentinel  = firstItem + numPerPage;
            sentinel  = (sentinel > numItems - 1) ? numItems - 1 : sentinel;
            rv = carousel.fireEvent(beforeScrollEvent,
                    { dir: direction, first: firstItem, last: sentinel });
            if (rv === false) { // scrolling is prevented
                return;
            }

            carousel.fireEvent(beforePageChangeEvent, { page: page });

            // call loaditems to check if we have all the items to display
            lastItem = item + numPerPage - 1;
            carousel._loadItems(lastItem > numItems-1 ? numItems-1 : lastItem);

            // Calculate the delta relative to the first item, the delta is
            // always negative.
            delta = 0 - item;

            if (itemsPerCol) {
            	// offset calculations for multirow Carousel
                if (isVertical) {
                    delta = parseInt(delta / itemsPerRow, 10);
                } else {
                    delta = parseInt(delta / itemsPerCol, 10);
                }
            }

            // adjust for items not yet loaded
            index = 0;
            while (delta < 0 && index < item+numPerPage-1 && index < numItems) {
                if (!items[index] && !loading[index]) {
                    delta++;
                }
                index += itemsPerCol ? itemsPerCol : 1;
            }

            carousel._firstItem = item;
            carousel.set("firstVisible", item);


            sentinel  = item + numPerPage;
            sentinel  = (sentinel > numItems - 1) ? numItems - 1 : sentinel;

            offset    = getScrollOffset.call(carousel, delta);

            animate   = animCfg.speed > 0;

            if (animate) {
                carousel._animateAndSetCarouselOffset(offset, item, sentinel,
                        dontSelect);
            } else {
                carousel._setCarouselOffset(offset);
                updateStateAfterScroll.call(carousel, item, sentinel);
            }
        },

        getPageForItem : function(item) {
            return Math.ceil(
                (item+1) / parseInt(this.get("numVisible"),10)
            );
        },

        getFirstVisibleOnPage : function(page) {
            return (page - 1) * this.get("numVisible");
        },

        selectPreviousItem: function () {
            var carousel = this,
                newpos   = 0,
                selected = carousel.get("selectedItem");

            if (selected == this._firstItem) {
                newpos = selected - carousel.get("numVisible");
                carousel._selectedItem = carousel._getSelectedItem(selected-1);
                carousel.scrollTo(newpos);
            } else {
                newpos = carousel.get("selectedItem") -
                         carousel.get("scrollIncrement");
                carousel.set("selectedItem",carousel._getSelectedItem(newpos));
            }
        },

        selectNextItem: function () {
            var carousel = this, newpos = 0;

            newpos = carousel.get("selectedItem") +
                     carousel.get("scrollIncrement");
            carousel.set("selectedItem", carousel._getSelectedItem(newpos));
        },

        show: function () {
            var carousel = this,
                cssClass = carousel.CLASSES;

            if (carousel.fireEvent(beforeShowEvent) !== false) {
                carousel.addClass(cssClass.VISIBLE);
                carousel.fireEvent(showEvent);
            }
        },

        startAutoPlay: function () {
            var carousel = this, timer;

            if (JS.isUndefined(carousel._autoPlayTimer)) {
                timer = carousel.get("autoPlayInterval");
                if (timer <= 0) {
                    return;
                }
                carousel._isAutoPlayInProgress = true;
                carousel.fireEvent(startAutoPlayEvent);
                carousel._autoPlayTimer = setTimeout(function () {
                    carousel._autoScroll();
                }, timer);
            }
        },

        stopAutoPlay: function () {
            var carousel = this;

            if (!JS.isUndefined(carousel._autoPlayTimer)) {
                clearTimeout(carousel._autoPlayTimer);
                delete carousel._autoPlayTimer;
                carousel._isAutoPlayInProgress = false;
                carousel.fireEvent(stopAutoPlayEvent);
            }
        },

        updatePagination: function () {
            var carousel = this,
                pagination = carousel._pagination;
            if(!pagination.el){ return false; }

            var numItems = carousel.get('numItems'),
                numVisible = carousel.get('numVisible'),
                firstVisible = carousel.get('firstVisible')+1,
                currentPage = carousel.get('currentPage')+1,
                numPages = carousel.get('numPages'),
                replacements = {
                    'numVisible' : numVisible,
                    'numPages' : numPages,
                    'numItems' : numItems,
                    'selectedItem' : carousel.get('selectedItem')+1,
                    'currentPage' : currentPage,
                    'firstVisible' : firstVisible,
                    'lastVisible' : carousel.get("lastVisible")+1
                },
                cb = pagination.callback || {},
                scope = cb.scope && cb.obj ? cb.obj : carousel;

            pagination.el.innerHTML = JS.isFunction(cb.fn) ? cb.fn.apply(scope, [pagination.template, replacements]) : YAHOO.lang.substitute(pagination.template, replacements);
        },

        registerPagination: function (tpl, pos, cb) {
            var carousel = this;

            carousel._pagination.template = tpl;
            carousel._pagination.callback = cb || {};

            if(!carousel._pagination.el){
                carousel._pagination.el = createElement('DIV', {className:carousel.CLASSES.PAGINATION});

                if(pos == "before"){
                    carousel._navEl.insertBefore(carousel._pagination.el, carousel._navEl.firstChild);
                } else {
                    carousel._navEl.appendChild(carousel._pagination.el);
                }

                carousel.on('itemSelected', carousel.updatePagination);
                carousel.on('pageChange', carousel.updatePagination);
            }

            carousel.updatePagination();
        },

        toString: function () {
            return WidgetName + (this.get ? " (#" + this.get("id") + ")" : "");
        },

        _animateAndSetCarouselOffset: function (offset, item, sentinel) {
            var carousel = this,
                animCfg  = carousel.get("animation"),
                animObj  = null;
                nextAnimObj  = null;

            if (carousel.get("isVertical")) {
                animObj = new YAHOO.util.Motion(carousel._carouselEl,
                        { top: { to: offset } },
                        animCfg.speed, animCfg.effect);
            } else if (carousel.get("isFading")) {
            	objItem = carousel.getVisibleItems();
            	objItem = objItem[0];
            	
            	prevItem = item - 1;
            	if ( prevItem < 0 ){
            		prevItem = carousel._itemsTable.numItems - 1;
            	}
                animObj = new YAHOO.util.Anim(carousel.getElementForItem(carousel.get("selectedItem")),
                        { opacity: {from: 1, to: 0 }},
                        animCfg.speed, animCfg.effect);
				
	            nextAnimObj = new YAHOO.util.Anim( carousel.getElementForItem( item ),
                        { opacity: {from: 0, to: 1 }},
                        animCfg.speed, animCfg.effect);
            } else {
                animObj = new YAHOO.util.Motion(carousel._carouselEl,
                        { left: { to: offset } },
                        animCfg.speed, animCfg.effect);
            }

            carousel._isAnimationInProgress = true;
            animObj.onComplete.subscribe(carousel._animationCompleteHandler,
                                         { scope: carousel, item: item,
                                           last: sentinel });
            animObj.animate();
            if ( nextAnimObj ){
            	nextAnimObj.animate();
            }
        },

        _animationCompleteHandler: function (ev, p, o) {
            o.scope._isAnimationInProgress = false;
            updateStateAfterScroll.call(o.scope, o.item, o.last);
        },

        _autoScroll: function() {
            var carousel  = this,
                currIndex = carousel._firstItem,
                index;

            if (currIndex >= carousel.get("numItems") - 1) {
                if (carousel.get("isCircular")) {
                    index = 0;
                } else {
                    carousel.stopAutoPlay();
                }
            } else {
                index = currIndex + carousel.get("numVisible");
            }

            carousel._selectedItem = carousel._getSelectedItem(index);
            carousel.scrollTo.call(carousel, index);
        },

        _createCarousel: function (elId) {
            var carousel = this,
                cssClass = carousel.CLASSES,
                el       = Dom.get(elId);

            if (!el) {
                el = createElement("DIV", {
                        className : cssClass.CAROUSEL,
                        id        : elId
                });
            }

            if (!carousel._carouselEl) {
                carousel._carouselEl=createElement(carousel.get("carouselEl"),
                        { className: cssClass.CAROUSEL_EL });
            }

            return el;
        },

        _createCarouselClip: function () {
            return createElement("DIV", { className: this.CLASSES.CONTENT });
        },

        _createCarouselItem: function (obj) {
            var attr, carousel = this,
                styles = getCarouselItemPosition.call(carousel, obj.pos);

            return createElement(carousel.get("carouselItemEl"), {
                    className : obj.className,
                    styles    : obj.styles,
                    content   : obj.content,
                    id        : obj.id
            });
        },

        _getValidIndex: function (index) {
            var carousel   = this,
                isCircular = carousel.get("isCircular"),
                numItems   = carousel.get("numItems"),
                numVisible = carousel.get("numVisible"),
                sentinel   = numItems - 1;

            if (index < 0) {
                index = isCircular ?
                        Math.ceil(numItems/numVisible)*numVisible + index : 0;
            } else if (index > sentinel) {
                index = isCircular ? 0 : sentinel;
            }

            return index;
        },

        _getSelectedItem: function (val) {
            var carousel   = this,
                isCircular = carousel.get("isCircular"),
                numItems   = carousel.get("numItems"),
                sentinel   = numItems - 1;

            if (val < 0) {
                if (isCircular) {
                    val = numItems + val;
                } else {
                    val = carousel.get("selectedItem");
                }
            } else if (val > sentinel) {
                if (isCircular) {
                    val = val - numItems;
                } else {
                    val = carousel.get("selectedItem");
                }
            }
            return val;
        },

        _itemClickHandler: function (ev) {
            var carousel     = this,
                carouselItem = carousel.get("carouselItemEl"),
                container    = carousel.get("element"),
                el,
                item,
                target       = Event.getTarget(ev),
                tag          = target.tagName.toUpperCase();

            if(tag === "INPUT" ||
               tag === "SELECT" ||
               tag === "TEXTAREA") {
                return;
            }

            while (target && target != container &&
                   target.id != carousel._carouselEl) {
                el = target.nodeName;
                if (el.toUpperCase() == carouselItem) {
                    break;
                }
                target = target.parentNode;
            }

            if ((item = carousel.getItemPositionById(target.id)) >= 0) {
                carousel.set("selectedItem", carousel._getSelectedItem(item));
                carousel.focus();
            }
        },

        _keyboardEventHandler: function (ev) {
            var carousel = this,
                key      = Event.getCharCode(ev),
                target   = Event.getTarget(ev),
                prevent  = false;

            // do not mess while animation is in progress or naving via select
            if (carousel.isAnimating() || target.tagName.toUpperCase() === "SELECT") {
                return;
            }

            switch (key) {
            case 0x25:          // left arrow
            case 0x26:          // up arrow
                carousel.selectPreviousItem();
                prevent = true;
                break;
            case 0x27:          // right arrow
            case 0x28:          // down arrow
                carousel.selectNextItem();
                prevent = true;
                break;
            case 0x21:          // page-up
                carousel.scrollPageBackward();
                prevent = true;
                break;
            case 0x22:          // page-down
                carousel.scrollPageForward();
                prevent = true;
                break;
            }

            if (prevent) {
                if (carousel.isAutoPlayOn()) {
                    carousel.stopAutoPlay();
                }
                Event.preventDefault(ev);
            }
        },

        _loadItems: function(last) {
            var carousel    = this,
                numItems    = carousel.get("numItems"),
                numVisible  = carousel.get("numVisible"),
                reveal      = carousel.get("revealAmount"),
                first       = carousel._itemsTable.items.length,
                lastVisible = carousel.get("lastVisible");

            // adjust if going backwards
            if(first > last && last+1 >= numVisible){
                // need to get first a bit differently for the last page
                first = last % numVisible || last == lastVisible ? last - last % numVisible : last - numVisible + 1;
            }

            if(reveal && last < numItems - 1){ last++; }

            if (last >= first && (!carousel.getItem(first) || !carousel.getItem(last))) {
                carousel.fireEvent(loadItemsEvent, {
                        ev: loadItemsEvent, first: first, last: last,
                        num: last - first + 1
                });
            }

        },

         _pagerChangeHandler: function (ev) {
            var carousel = this,
                target = Event.getTarget(ev),
                 page = target.value,
                 item;

             if (page) {
                 item = carousel.getFirstVisibleOnPage(page);
                 carousel._selectedItem = item;
                 carousel.scrollTo(item);
                 carousel.focus();
            }
          },
          
         _pagerClickHandler: function (ev) {
             var carousel = this,
                 css = carousel.CLASSES,
                 target = Event.getTarget(ev),
                 elNode = target.nodeName.toUpperCase(),
                 val,
                 stringIndex,
                 page,
                 item;

             if (Dom.hasClass(target, css.PAGER_ITEM) || Dom.hasClass(target.parentNode, css.PAGER_ITEM))  {
                 if (elNode == "EM") {
                     target = target.parentNode;// item is an em and not an anchor (when text is visible)
                 }
                 val = target.href;
                 stringIndex = val.lastIndexOf("#");
                 page =  parseInt(val.substring(stringIndex+1), 10);
                    if (page != -1) {
                     item = carousel.getFirstVisibleOnPage(page);
                     carousel._selectedItem = item;
                     carousel.scrollTo(item);
                            carousel.focus();
                        }
                        Event.preventDefault(ev);
                    }
        },

        _parseCarousel: function (parent) {
            var carousel = this, child, cssClass, domEl, found, node;

            cssClass  = carousel.CLASSES;
            domEl     = carousel.get("carouselEl");
            found     = false;

            for (child = parent.firstChild; child; child = child.nextSibling) {
                if (child.nodeType == 1) {
                    node = child.nodeName;
                    if (node.toUpperCase() == domEl) {
                        carousel._carouselEl = child;
                        Dom.addClass(carousel._carouselEl,
                                     carousel.CLASSES.CAROUSEL_EL);
                        found = true;
                    }
                }
            }

            return found;
        },

        _parseCarouselItems: function () {
            var carousel = this,
                cssClass = carousel.CLASSES,
                i=0,
                rows,
                child,
                domItemEl,
                elId,
                node,
                index = carousel.get("firstVisible"),
                parent   = carousel._carouselEl;

            rows = carousel._rows;
            domItemEl = carousel.get("carouselItemEl");

            for (child = parent.firstChild; child; child = child.nextSibling) {
                if (child.nodeType == 1) {
                    node = child.nodeName;
                    if (node.toUpperCase() == domItemEl) {
                        if (child.id) {
                            elId = child.id;
                        } else {
                            elId = Dom.generateId();
                            child.setAttribute("id", elId);
                        }
                        carousel.addItem(child,index);
                        index++;
                    }
                }
            }
        },

        _parseCarouselNavigation: function (parent) {
            var carousel = this,
                cfg,
                cssClass = carousel.CLASSES,
                el,
                i,
                j,
                nav,
                rv       = false;

            nav = Dom.getElementsByClassName(cssClass.PREV_PAGE, "*", parent);
            if (nav.length > 0) {
                for (i in nav) {
                    if (nav.hasOwnProperty(i)) {
                        el = nav[i];
                        if (el.nodeName == "INPUT" ||
                            el.nodeName == "BUTTON" ||
                            el.nodeName == "A") {// Anchor support in Nav (for SEO)
                            carousel._navBtns.prev.push(el);
                        } else {
                            j = el.getElementsByTagName("INPUT");
                            if (JS.isArray(j) && j.length > 0) {
                                carousel._navBtns.prev.push(j[0]);
                            } else {
                                j = el.getElementsByTagName("BUTTON");
                                if (JS.isArray(j) && j.length > 0) {
                                    carousel._navBtns.prev.push(j[0]);
                                }
                            }
                        }
                    }
                }
                cfg = { prev: nav };
            }

            nav = Dom.getElementsByClassName(cssClass.NEXT_PAGE, "*", parent);
            if (nav.length > 0) {
                for (i in nav) {
                    if (nav.hasOwnProperty(i)) {
                        el = nav[i];
                        if (el.nodeName == "INPUT" ||
                            el.nodeName == "BUTTON" ||
                            el.nodeName == "A") {// Anchor support in Nav (for SEO)
                            carousel._navBtns.next.push(el);
                        } else {
                            j = el.getElementsByTagName("INPUT");
                            if (JS.isArray(j) && j.length > 0) {
                                carousel._navBtns.next.push(j[0]);
                            } else {
                                j = el.getElementsByTagName("BUTTON");
                                if (JS.isArray(j) && j.length > 0) {
                                    carousel._navBtns.next.push(j[0]);
                                }
                            }
                        }
                    }
                }
                if (cfg) {
                    cfg.next = nav;
                } else {
                    cfg = { next: nav };
                }
            }

            if (cfg) {
                carousel.set("navigation", cfg);
                rv = true;
            }

            return rv;
        },

        _refreshUi: function () {
            var carousel = this, i, isVertical = carousel.get("isVertical"), firstVisible = carousel.get("firstVisible"), item, n, rsz, sz;

            if (carousel._itemsTable.numItems < 1) {
                return;
            }

            sz  = getCarouselItemSize.call(carousel,
                    isVertical ? "height" : "width");
            // This fixes the widget to auto-adjust height/width for absolute
            // positioned children.
            item = carousel._itemsTable.items[firstVisible].id;

            sz   = isVertical ? getStyle(item, "width") :
                    getStyle(item, "height");

            Dom.setStyle(carousel._carouselEl,
                         isVertical ? "width" : "height", sz + "px");

            // Set the rendered state appropriately.
            carousel._hasRendered = true;
            carousel.fireEvent(renderEvent);
        },

        _setCarouselOffset: function (offset) {
            var carousel = this, which;

            which = carousel.get("isVertical") ? "top" : "left";
            Dom.setStyle(carousel._carouselEl, which, offset + "px");
        },

        _setupCarouselNavigation: function () {
            var carousel = this,
                btn, cfg, cssClass, nav, navContainer, nextButton, prevButton;

            cssClass = carousel.CLASSES;

            // TODO: can the _navBtns be tested against instead?
            navContainer = Dom.getElementsByClassName(cssClass.NAVIGATION,
                    "DIV", carousel.get("element"));

            if (navContainer.length === 0) {
                navContainer = createElement("DIV",
                        { className: cssClass.NAVIGATION });
                carousel.insertBefore(navContainer,
                        Dom.getFirstChild(carousel.get("element")));
            } else {
                navContainer = navContainer[0];
            }

            carousel._pages.el = createElement("UL");
            navContainer.appendChild(carousel._pages.el);

            nav = carousel.get("navigation");
            if (JS.isString(nav.prev) || JS.isArray(nav.prev)) {
                if (JS.isString(nav.prev)) {
                    nav.prev = [nav.prev];
                }
                for (btn in nav.prev) {
                    if (nav.prev.hasOwnProperty(btn)) {
                        carousel._navBtns.prev.push(Dom.get(nav.prev[btn]));
                    }
                }
            } else {
                // TODO: separate method for creating a navigation button
                prevButton = createElement("SPAN",
                        { className: cssClass.BUTTON + cssClass.FIRST_NAV });
                // XXX: for IE 6.x
                Dom.setStyle(prevButton, "visibility", "visible");
                btn = Dom.generateId();
                prevButton.innerHTML = "<button type=\"button\" "      +
                        "id=\"" + btn + "\" name=\""                   +
                        carousel.STRINGS.PREVIOUS_BUTTON_TEXT + "\">"  +
                        carousel.STRINGS.PREVIOUS_BUTTON_TEXT + "</button>";
                navContainer.appendChild(prevButton);
                btn = Dom.get(btn);
                carousel._navBtns.prev = [btn];
                cfg = { prev: [prevButton] };
            }

            if (JS.isString(nav.next) || JS.isArray(nav.next)) {
                if (JS.isString(nav.next)) {
                    nav.next = [nav.next];
                }
                for (btn in nav.next) {
                    if (nav.next.hasOwnProperty(btn)) {
                        carousel._navBtns.next.push(Dom.get(nav.next[btn]));
                    }
                }
            } else {
                // TODO: separate method for creating a navigation button
                nextButton = createElement("SPAN",
                        { className: cssClass.BUTTON + cssClass.NEXT_NAV });
                // XXX: for IE 6.x
                Dom.setStyle(nextButton, "visibility", "visible");
                btn = Dom.generateId();
                nextButton.innerHTML = "<button type=\"button\" "      +
                        "id=\"" + btn + "\" name=\""                   +
                        carousel.STRINGS.NEXT_BUTTON_TEXT + "\">"      +
                        carousel.STRINGS.NEXT_BUTTON_TEXT + "</button>";
                navContainer.appendChild(nextButton);
                btn = Dom.get(btn);
                carousel._navBtns.next = [btn];
                if (cfg) {
                    cfg.next = [nextButton];
                } else {
                    cfg = { next: [nextButton] };
                }
            }

            if (cfg) {
                carousel.set("navigation", cfg);
            }

            return navContainer;
        },

        _setClipContainerSize: function (clip, num) {
            var carousel   = this,
                isVertical = carousel.get("isVertical"),
                rows       = carousel._rows,
                cols       = carousel._cols,
                reveal     = carousel.get("revealAmount"),
                itemHeight = getCarouselItemSize.call(carousel, "height"),
                itemWidth  = getCarouselItemSize.call(carousel, "width"),
                containerHeight,
                containerWidth;

            clip = clip || carousel._clipEl;

            if (rows) {
                 containerHeight = itemHeight * rows;
                 containerWidth  = itemWidth  * cols;
            } else {
                num = num || carousel.get("numVisible");
                if (isVertical) {
                    containerHeight = itemHeight * num;
                } else {
                    containerWidth  = itemWidth  * num;
                }
            }

            // TODO: try to re-use the _hasRendered indicator

            carousel._recomputeSize = (containerHeight === 0); // bleh!
            if (carousel._recomputeSize) {
                carousel._hasRendered = false;
                return;             // no use going further, bail out!
            }

            reveal = getRevealSize.call(carousel);
            if (isVertical) {
                containerHeight += (reveal * 2);
            } else {
                containerWidth  += (reveal * 2);
            }

            if (isVertical) {
                containerHeight += getDimensions(carousel._carouselEl,"height");
                Dom.setStyle(clip, "height", containerHeight + "px");
                // For multi-row Carousel
                if (cols) {
                    containerWidth += getDimensions(carousel._carouselEl,
                            "width");
                    Dom.setStyle(clip, "width", containerWidth + (0) + "px");
                }
            } else {
                containerWidth += getDimensions(carousel._carouselEl, "width");
                Dom.setStyle(clip, "width", containerWidth + "px");
                // For multi-row Carousel
                if (rows) {
                    containerHeight += getDimensions(carousel._carouselEl,
                            "height");
                    Dom.setStyle(clip, "height", containerHeight + "px");
                }
            }

            carousel._setContainerSize(clip); // adjust the container size too
        },

        _setContainerSize: function (clip, attr) {
            var carousel = this,
                config   = carousel.CONFIG,
                cssClass = carousel.CLASSES,
                isVertical,
                rows,
                cols,
                size;

            isVertical = carousel.get("isVertical");
            rows       = carousel._rows;
            cols       = carousel._cols;
            clip       = clip || carousel._clipEl;
            attr       = attr || (isVertical ? "height" : "width");
            size       = parseFloat(Dom.getStyle(clip, attr), 10);

            size = JS.isNumber(size) ? size : 0;

            if (isVertical) {
                size += getDimensions(carousel._carouselEl, "height") +
                        getStyle(carousel._navEl, "height");
            } else {
                size += getDimensions(carousel._carouselEl, "width");
            }

            if (!isVertical) {
                if (size < config.HORZ_MIN_WIDTH) {
                    size = config.HORZ_MIN_WIDTH;
                    carousel.addClass(cssClass.MIN_WIDTH);
                }
            }
            carousel.setStyle(attr,  size + "px");

            // Additionally the width of the container should be set for
            // the vertical Carousel
            if (isVertical) {
                size = getCarouselItemSize.call(carousel, "width");
                if(cols) {
                    size = size * cols;
                }
                Dom.setStyle(carousel._carouselEl, "width", size + "px");// Bug fix for vertical carousel (goes in conjunction with .yui-carousel-element {... 3200px removed from styles), and allows for multirows in IEs).
                if (size < config.VERT_MIN_WIDTH) {
                    size = config.VERT_MIN_WIDTH;
                    carousel.addClass(cssClass.MIN_WIDTH);// set a min width on vertical carousel, don't see why this shouldn't always be set...
                }
                carousel.setStyle("width",  size + "px");
            } else {
                if(rows) {
                    size = getCarouselItemSize.call(carousel, "height");
                    size = size * rows;
                    Dom.setStyle(carousel._carouselEl, "height", size + "px");
                }
            }
        },

        _setFirstVisible: function (val) {
            var carousel = this;

            if (val >= 0 && val < carousel.get("numItems")) {
                carousel.scrollTo(val);
            } else {
                val = carousel.get("firstVisible");
            }
            return val;
        },

        _setNavigation: function (cfg) {
            var carousel = this;

            if (cfg.prev) {
                Event.on(cfg.prev, "click", scrollPageBackward, carousel);
            }
            if (cfg.next) {
                Event.on(cfg.next, "click", scrollPageForward, carousel);
            }
        },

        _setNumVisible: function (val) { // TODO: _setNumVisible should just be reserved for setting numVisible.
            var carousel = this;

            carousel._setClipContainerSize(carousel._clipEl, val);
        },

        _numVisibleSetter: function (val) {
            var carousel = this,
                numVisible = val;

            if(JS.isArray(val)) {
                carousel._cols = val[0];
                carousel._rows = val[1];
                numVisible = val[0] *  val[1];
            }
            return numVisible;
        },

        _selectedItemSetter: function (val) {
            var carousel = this;
            return (val < carousel.get("numItems")) ? val : 0;
        },

        _setNumItems: function (val) {
            var carousel = this,
                num      = carousel._itemsTable.numItems;

            if (JS.isArray(carousel._itemsTable.items)) {
                if (carousel._itemsTable.items.length != num) { // out of sync
                    num = carousel._itemsTable.items.length;
                    carousel._itemsTable.numItems = num;
                }
            }

            if (val < num) {
                while (num > val) {
                    carousel.removeItem(num - 1);
                    num--;
                }
            }

            return val;
        },

        _setOrientation: function (val) {
            var carousel = this,
                cssClass = carousel.CLASSES;

            if (val) {
                carousel.replaceClass(cssClass.HORIZONTAL, cssClass.VERTICAL);
            } else {
                carousel.replaceClass(cssClass.VERTICAL, cssClass.HORIZONTAL);
            }
            this._itemAttrCache = {}; // force recomputed next time

            return val;
        },

        _setRevealAmount: function (val) {
            var carousel = this;

            if (val >= 0 && val <= 100) {
                val = parseInt(val, 10);
                val = JS.isNumber(val) ? val : 0;
                carousel._setClipContainerSize();
            } else {
                val = carousel.get("revealAmount");
            }
            return val;
        },

        _setSelectedItem: function (val) {
            this._selectedItem = val;
        },

        _getNumPages: function () {
            return Math.ceil(
                parseInt(this.get("numItems"),10) / parseInt(this.get("numVisible"),10)
            );
        },

        _getLastVisible: function () {
            var carousel = this;
            return carousel.get("currentPage") + 1 == carousel.get("numPages") ?
                   carousel.get("numItems") - 1:
                   carousel.get("firstVisible") + carousel.get("numVisible") - 1;
        },

        _syncUiForItemAdd: function (obj) {
            var attr,
                carousel   = this,
                carouselEl = carousel._carouselEl,
                el,
                item,
                itemsTable = carousel._itemsTable,
                oel,
                pos,
                sibling,
                styles;

            pos  = JS.isUndefined(obj.pos) ?
                   obj.newPos || itemsTable.numItems - 1 : obj.pos;

            if (!oel) {
                item = itemsTable.items[pos] || {};
                el = carousel._createCarouselItem({
                        className : item.className,
                        styles    : item.styles,
                        content   : item.item,
                        id        : item.id,
                        pos       : pos
                });
                if (JS.isUndefined(obj.pos)) {
                    if (!JS.isUndefined(itemsTable.loading[pos])) {
                        oel = itemsTable.loading[pos];
                        // if oel is null, it is a problem ...
                    }
                    if (oel) {
                        // replace the node
                        carouselEl.replaceChild(el, oel);
                        // ... and remove the item from the data structure
                        delete itemsTable.loading[pos];
                    } else {
                        carouselEl.appendChild(el);
                    }
                } else {
                    if (!JS.isUndefined(itemsTable.items[obj.pos + 1])) {
                        sibling = Dom.get(itemsTable.items[obj.pos + 1].id);
                    }
                    if (sibling) {
                        carouselEl.insertBefore(el, sibling);
                    } else {
                    }
                }
            } else {
                if (JS.isUndefined(obj.pos)) {
                    if (!Dom.isAncestor(carousel._carouselEl, oel)) {
                        carouselEl.appendChild(oel);
                    }
                } else {
                    if (!Dom.isAncestor(carouselEl, oel)) {
                        if (!JS.isUndefined(itemsTable.items[obj.pos + 1])) {
                            carouselEl.insertBefore(oel,
                                    Dom.get(itemsTable.items[obj.pos + 1].id));
                        }
                    }
                }
            }

            if (!carousel._hasRendered) {
                carousel._refreshUi();
            }

            if (carousel.get("selectedItem") < 0) {
                carousel.set("selectedItem", carousel.get("firstVisible"));
            }

            carousel._syncUiItems();
        },

        _syncUiForItemReplace: function (o) {
            var carousel   = this,
                carouselEl = carousel._carouselEl,
                itemsTable = carousel._itemsTable,
                pos        = o.pos,
                item       = o.newItem,
                oel        = o.oldItem,
                el;

            el = carousel._createCarouselItem({
                className : item.className,
                styles    : item.styles,
                content   : item.item,
                id        : item.id,
                pos       : pos
            });

            if(el && oel) {
                Event.purgeElement(oel, true);
                carouselEl.replaceChild(el, Dom.get(oel.id));
                if (!JS.isUndefined(itemsTable.loading[pos])) {
                    itemsTable.numItems++;
                    delete itemsTable.loading[pos];
                }
            }
            // TODO: should we add the item if oel is undefined?

            if (!carousel._hasRendered) {
                carousel._refreshUi();
            }

            carousel._syncUiItems();
        },

        _syncUiForItemRemove: function (obj) {
            var carousel   = this,
                carouselEl = carousel._carouselEl,
                el, item, num, pos;

            num  = carousel.get("numItems");
            item = obj.item;
            pos  = obj.pos;

            if (item && (el = Dom.get(item.id))) {
                if (el && Dom.isAncestor(carouselEl, el)) {
                    Event.purgeElement(el, true);
                    carouselEl.removeChild(el);
                }

                if (carousel.get("selectedItem") == pos) {
                    pos = pos >= num ? num - 1 : pos;
                }
            } else {
            }

            carousel._syncUiItems();
        },

        _syncUiForLazyLoading: function (obj) {
            var carousel   = this,
                carouselEl = carousel._carouselEl,
                itemsTable = carousel._itemsTable,
                len = itemsTable.items.length,
                sibling = itemsTable.items[obj.last + 1],
                el,
                j;

            // attempt to find the next closest sibling
            if(!sibling && obj.last < len){
                j = obj.first;
                do {
                    sibling = itemsTable.items[j];
                    j++;
                } while (j<len && !sibling);
            }

            for (var i = obj.first; i <= obj.last; i++) {
                if(JS.isUndefined(itemsTable.loading[i]) && JS.isUndefined(itemsTable.items[i])){
                    el = carousel._createCarouselItem({
                            className : carousel.CLASSES.ITEM_LOADING,
                            content   : carousel.STRINGS.ITEM_LOADING_CONTENT,
                            id        : Dom.generateId(),
                            pos       : i
                    });
                    if (el) {
                        if (sibling) {
                            sibling = Dom.get(sibling.id);
                            if (sibling) {
                                carouselEl.insertBefore(el, sibling);
                            } else {
                            }
                        } else {
                            carouselEl.appendChild(el);
                        }
                    }
                    itemsTable.loading[i] = el;
                }
            }

            carousel._syncUiItems();
        },

        _syncUiItems: function () {
            var attr,
                carousel = this,
                numItems = carousel.get("numItems"),
                i,
                itemsTable = carousel._itemsTable,
                items = itemsTable.items,
                loading = itemsTable.loading,
                item,
                styles;

            for (i = 0; i < numItems; i++) {
                item = items[i] || loading[i];

                if (item && item.id) {
                    styles = getCarouselItemPosition.call(carousel, i);
                    item.styles = item.styles || {};
                    for (attr in styles) {
                        if (styles.hasOwnProperty(attr)) {
                            item.styles[attr] = styles[attr];
                        }
                    }
                    setStyles(Dom.get(item.id), styles);
                }
            }
        },

        _updateNavButtons: function (el, setFocus) {
            var children,
                cssClass = this.CLASSES,
                grandParent,
                parent   = el.parentNode;

            if (!parent) {
                return;
            }
            grandParent = parent.parentNode;

            if (el.nodeName.toUpperCase() == "BUTTON" &&
                Dom.hasClass(parent, cssClass.BUTTON)) {
                if (setFocus) {
                    if (grandParent) {
                        children = Dom.getChildren(grandParent);
                        if (children) {
                            Dom.removeClass(children, cssClass.FOCUSSED_BUTTON);
                        }
                    }
                    Dom.addClass(parent, cssClass.FOCUSSED_BUTTON);
                } else {
                    Dom.removeClass(parent, cssClass.FOCUSSED_BUTTON);
                }
            }
        },

         _updatePagerButtons: function () {
             var carousel = this,
                 css      = carousel.CLASSES,
                 cur      = carousel._pages.cur, // current page
                 el,
                 html,
                 i,
                 item,
                 n        = carousel.get("numVisible"),
                 num      = carousel._pages.num, // total pages
                 pager    = carousel._pages.el;  // the pager container element

             if (num === 0 || !pager) {
                 return;         // don't do anything if number of pages is 0
             }

             // Hide the pager before redrawing it
             Dom.setStyle(pager, "visibility", "hidden");

             // Remove all nodes from the pager
             while (pager.firstChild) {
                 pager.removeChild(pager.firstChild);
             }

             for (i = 0; i < num; i++) {

                 el   = document.createElement("LI");

                 if (i === 0) {
                     Dom.addClass(el, css.FIRST_PAGE);
                 }
                 if (i == cur) {
                     Dom.addClass(el, css.SELECTED_NAV);
                 }

                 html = "<a class=" + css.PAGER_ITEM + " href=\"#" + (i+1) + "\" tabindex=\"0\"><em>"   +
                         carousel.STRINGS.PAGER_PREFIX_TEXT + + (i+1) +
                         "</em></a>";
                 el.innerHTML = html;

                 pager.appendChild(el);
             }

             // Show the pager now
             Dom.setStyle(pager, "visibility", "visible");
         },

        _updatePagerMenu: function () {
            var carousel = this,
                css      = carousel.CLASSES,
                cur      = carousel._pages.cur, // current page
                el,
                i,
                item,
                n        = carousel.get("numVisible"),
                num      = carousel._pages.num, // total pages
                pager    = carousel._pages.el,  // the pager container element
                sel;

            if (num === 0) {
                return;// don't do anything if number of pages is 0
            }

            sel = document.createElement("SELECT");


            if (!sel) {
                return;
            }

            // Hide the pager before redrawing it
            Dom.setStyle(pager, "visibility", "hidden");

            // Remove all nodes from the pager
            while (pager.firstChild) {
                pager.removeChild(pager.firstChild);
            }

            for (i = 0; i < num; i++) {

                el   = document.createElement("OPTION");
                el.value     = i+1;
                el.innerHTML = carousel.STRINGS.PAGER_PREFIX_TEXT +(i+1);

                if (i == cur) {
                    el.setAttribute("selected", "selected");
                }

                sel.appendChild(el);
            }

            el = document.createElement("FORM");
            if (!el) {
            } else {
                el.appendChild(sel);
                pager.appendChild(el);
            }

            // Show the pager now
            Event.addListener(sel, "change", carousel._pagerChangeHandler, this, true);
            Dom.setStyle(pager, "visibility", "visible");
        },

        _updateTabIndex: function (el) {
            var carousel = this;

            if (el) {
                if (carousel._focusableItemEl) {
                    carousel._focusableItemEl.tabIndex = -1;
                }
                carousel._focusableItemEl = el;
                el.tabIndex = 0;
            }
        },

        _validateAnimation: function (cfg) {
            var rv = true;

            if (JS.isObject(cfg)) {
                if (cfg.speed) {
                    rv = rv && JS.isNumber(cfg.speed);
                }
                if (cfg.effect) {
                    rv = rv && JS.isFunction(cfg.effect);
                } else if (!JS.isUndefined(YAHOO.util.Easing)) {
                    cfg.effect = YAHOO.util.Easing.easeOut;
                }
            } else {
                rv = false;
            }

            return rv;
        },

        _validateFirstVisible: function (val) {
            var carousel = this, numItems = carousel.get("numItems");

            if (JS.isNumber(val)) {
                if (numItems === 0 && val == numItems) {
                    return true;
                } else {
                    return (val >= 0 && val < numItems);
                }
            }

            return false;
        },

        _validateNavigation : function (cfg) {
            var i;

            if (!JS.isObject(cfg)) {
                return false;
            }

            if (cfg.prev) {
                if (!JS.isArray(cfg.prev)) {
                    return false;
                }
                for (i in cfg.prev) {
                    if (cfg.prev.hasOwnProperty(i)) {
                        if (!JS.isString(cfg.prev[i].nodeName)) {
                            return false;
                        }
                    }
                }
            }

            if (cfg.next) {
                if (!JS.isArray(cfg.next)) {
                    return false;
                }
                for (i in cfg.next) {
                    if (cfg.next.hasOwnProperty(i)) {
                        if (!JS.isString(cfg.next[i].nodeName)) {
                            return false;
                        }
                    }
                }
            }

            return true;
        },

        _validateNumItems: function (val) {
            return JS.isNumber(val) && (val >= 0);
        },

        _validateNumVisible: function (val) {
            var rv = false;

            if (JS.isNumber(val)) {
                rv = val > 0 && val <= this.get("numItems");
            } else if (JS.isArray(val)) {
                if (JS.isNumber(val[0]) && JS.isNumber(val[1])) {
                    rv = val[0] * val[1] > 0 && val.length == 2;
                }
            }

            return rv;
        },

        _validateRevealAmount: function (val) {
            var rv = false;

            if (JS.isNumber(val)) {
                rv = val >= 0 && val < 100;
            }

            return rv;
        },

        _validateScrollIncrement: function (val) {
            var rv = false;

            if (JS.isNumber(val)) {
                rv = (val > 0 && val < this.get("numItems"));
            }

            return rv;
        }

    });

})();

YAHOO.register("carousel", YAHOO.widget.Carousel, {version: "2.8.2r1", build: "7"});

adjustSlideShowHeight = function( idWidgetApplication ){
	intH = 0;
	w_slidesshow_li = YAHOO.util.Dom.getChildren( 'w_slideshowContents_' + idWidgetApplication );
	for( i= 0; i!=w_slidesshow_li.length - 1; i++){
		if (w_slidesshow_li[i].scrollHeight > intH ) {
			intH = w_slidesshow_li[i].scrollHeight;
		}
	}
	YAHOO.util.Dom.setStyle( 'w_slideshowContents_' + idWidgetApplication, 'height', intH + 'px' );
}
