/**
 * jCarousel - Riding carousels with jQuery
 *   http://sorgalla.com/jcarousel/
 *
 * Copyright (c) 2006 Jan Sorgalla (http://sorgalla.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Built on top of the jQuery library
 *   http://jquery.com
 *
 * Inspired by the "Carousel Component" by Bill Scott
 *   http://billwscott.com/carousel/
 */
/*eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(9($){$.1w.B=9(o){z 4.1c(9(){3j r(4,o)})};8 q={Y:I,26:1,1W:1,u:7,18:3,17:7,1O:\'2O\',2b:\'2F\',1i:0,C:7,1h:7,1D:7,2y:7,2w:7,2v:7,2t:7,2s:7,2q:7,2p:7,1P:\'<X></X>\',1N:\'<X></X>\',2m:\'2l\',2j:\'2l\',1H:7,1J:7,2g:15};$.B=9(e,o){4.5=$.19({},q,o||{});4.P=I;4.F=7;4.H=7;4.t=7;4.Q=7;4.R=7;4.O=!4.5.Y?\'1E\':\'25\';4.E=!4.5.Y?\'24\':\'21\';6(e.2x==\'3n\'||e.2x==\'3m\'){4.t=$(e);4.F=4.t.1o();6($.D.1f(4.F[0].D,\'B-H\')){6(!$.D.1f(4.F[0].3k.D,\'B-F\'))4.F=4.F.C(\'<X></X>\');4.F=4.F.1o()}10 6(!$.D.1f(4.F[0].D,\'B-F\'))4.F=4.t.C(\'<X></X>\').1o();8 a=e.D.3d(\' \');1n(8 i=0;i<a.N;i++){6(a[i].3c(\'B-3a\')!=-1){4.t.1x(a[i]);4.F.T(a[i])}}}10{4.F=$(e);4.t=$(e).2o(\'31,2Y\')}4.H=4.t.1o();6(!4.H.N||!$.D.1f(4.H[0].D,\'B-H\'))4.H=4.t.C(\'<X></X>\').1o();4.R=$(\'.B-11\',4.F);6(4.R.u()==0&&4.5.1N!=7)4.R=4.H.1r(4.5.1N).11();4.R.T(4.D(\'B-11\'));4.Q=$(\'.B-16\',4.F);6(4.Q.u()==0&&4.5.1P!=7)4.Q=4.H.1r(4.5.1P).11();4.Q.T(4.D(\'B-16\'));4.H.T(4.D(\'B-H\'));4.t.T(4.D(\'B-t\'));4.F.T(4.D(\'B-F\'));8 b=4.5.17!=7?1l.1K(4.1m()/4.5.17):7;8 c=4.t.2o(\'1s\');8 d=4;6(c.u()>0){8 f=0,i=4.5.1W;c.1c(9(){d.1G(4,i++);f+=d.U(4,b)});6(4.5.2g)4.t.y(4.O,f+\'S\');6(!o||o.u==K)4.5.u=c.u()}4.F.y(\'1u\',\'1z\');4.Q.y(\'1u\',\'1z\');4.R.y(\'1u\',\'1z\');4.2r=9(){d.16()};4.2a=9(){d.11()};$(2C).1Y(\'2A\',9(){d.28()});6(4.5.1h!=7)4.5.1h(4,\'27\');4.1F()};8 r=$.B;r.1w=r.2z={B:\'0.2.2\'};r.1w.19=r.19=$.19;r.1w.19({1F:9(){4.A=7;4.G=7;4.V=7;4.12=7;4.14=I;4.1d=7;4.M=7;4.Z=I;6(4.P)z;4.t.y(4.E,4.1q(4.5.1W)+\'S\');8 p=4.1q(4.5.26);4.V=4.12=7;4.1g(p,I)},23:9(){4.t.22();4.t.y(4.E,\'20\');4.t.y(4.O,\'20\');6(4.5.1h!=7)4.5.1h(4,\'23\');4.1F()},28:9(){6(4.M!=7&&4.Z)4.t.y(4.E,r.L(4.t.y(4.E))+4.M);4.M=7;4.Z=I;6(4.5.1D!=7)4.5.1D(4);6(4.5.17!=7){8 a=4;8 b=1l.1K(4.1m()/4.5.17),O=0,E=0;$(\'1s\',4.t).1c(9(i){O+=a.U(4,b);6(i+1<a.A)E=O});4.t.y(4.O,O+\'S\');4.t.y(4.E,-E+\'S\')}4.18(4.A,I)},3q:9(){4.P=15;4.1p()},3o:9(){4.P=I;4.1p()},u:9(s){6(s!=K){4.5.u=s;6(!4.P)4.1p()}z 4.5.u},1f:9(i,a){6(a==K||!a)a=i;1n(8 j=i;j<=a;j++){8 e=4.J(j).J(0);6(!e||$.D.1f(e,\'B-1a-1C\'))z I}z 15},J:9(i){z $(\'.B-1a-\'+i,4.t)},3l:9(i,s){8 e=4.J(i),1V=0;6(e.N==0){8 c,e=4.1B(i),j=r.L(i);1k(c=4.J(--j)){6(j<=0||c.N){j<=0?4.t.2u(e):c.1U(e);1y}}}10 1V=4.U(e);e.1x(4.D(\'B-1a-1C\'));1T s==\'3h\'?e.3g(s):e.22().3f(s);8 a=4.5.17!=7?1l.1K(4.1m()/4.5.17):7;8 b=4.U(e,a)-1V;6(i>0&&i<4.A)4.t.y(4.E,r.L(4.t.y(4.E))+b+\'S\');4.t.y(4.O,r.L(4.t.y(4.O))+b+\'S\');z e},1S:9(i){8 e=4.J(i);6(!e.N||(i>=4.A&&i<=4.G))z;8 d=4.U(e);6(i<4.A)4.t.y(4.E,r.L(4.t.y(4.E))+d+\'S\');e.1S();4.t.y(4.O,r.L(4.t.y(4.O))-d+\'S\')},16:9(){4.1A();6(4.M!=7&&!4.Z)4.1R(I);10 4.18(((4.5.C==\'1Q\'||4.5.C==\'G\')&&4.5.u!=7&&4.G==4.5.u)?1:4.A+4.5.18)},11:9(){4.1A();6(4.M!=7&&4.Z)4.1R(15);10 4.18(((4.5.C==\'1Q\'||4.5.C==\'A\')&&4.5.u!=7&&4.A==1)?4.5.u:4.A-4.5.18)},1R:9(b){6(4.P||4.14||!4.M)z;8 a=r.L(4.t.y(4.E));!b?a-=4.M:a+=4.M;4.Z=!b;4.V=4.A;4.12=4.G;4.1g(a)},18:9(i,a){6(4.P||4.14)z;4.1g(4.1q(i),a)},1q:9(i){6(4.P||4.14)z;6(4.5.C!=\'1b\')i=i<1?1:(4.5.u&&i>4.5.u?4.5.u:i);8 a=4.A>i;8 b=r.L(4.t.y(4.E));8 f=4.5.C!=\'1b\'&&4.A<=1?1:4.A;8 c=a?4.J(f):4.J(4.G);8 j=a?f:f-1;8 e=7,l=0,p=I,d=0;1k(a?--j>=i:++j<i){e=4.J(j);p=!e.N;6(e.N==0){e=4.1B(j).T(4.D(\'B-1a-1C\'));c[a?\'1r\':\'1U\'](e)}c=e;d=4.U(e);6(p)l+=d;6(4.A!=7&&(4.5.C==\'1b\'||(j>=1&&(4.5.u==7||j<=4.5.u))))b=a?b+d:b-d}8 g=4.1m();8 h=[];8 k=0,j=i,v=0;8 c=4.J(i-1);1k(++k){e=4.J(j);p=!e.N;6(e.N==0){e=4.1B(j).T(4.D(\'B-1a-1C\'));c.N==0?4.t.2u(e):c[a?\'1r\':\'1U\'](e)}c=e;8 d=4.U(e);6(d==0){3b(\'39: 38 1E/25 37 1n 36. 35 34 33 32 30 2Z. 2X...\');z 0}6(4.5.C!=\'1b\'&&4.5.u!==7&&j>4.5.u)h.2W(e);10 6(p)l+=d;v+=d;6(v>=g)1y;j++}1n(8 x=0;x<h.N;x++)h[x].1S();6(l>0){4.t.y(4.O,4.U(4.t)+l+\'S\');6(a){b-=l;4.t.y(4.E,r.L(4.t.y(4.E))-l+\'S\')}}8 n=i+k-1;6(4.5.C!=\'1b\'&&4.5.u&&n>4.5.u)n=4.5.u;6(j>n){k=0,j=n,v=0;1k(++k){8 e=4.J(j--);6(!e.N)1y;v+=4.U(e);6(v>=g)1y}}8 o=n-k+1;6(4.5.C!=\'1b\'&&o<1)o=1;6(4.Z&&a){b+=4.M;4.Z=I}4.M=7;6(4.5.C!=\'1b\'&&n==4.5.u&&(n-k+1)>=1){8 m=r.W(4.J(n),!4.5.Y?\'1j\':\'1M\');6((v-m)>g)4.M=v-g-m}1k(i-->o)b+=4.U(4.J(i));4.V=4.A;4.12=4.G;4.A=o;4.G=n;z b},1g:9(p,a){6(4.P||4.14)z;4.14=15;8 b=4;8 c=9(){b.14=I;6(p==0)b.t.y(b.E,0);6(b.5.C==\'1Q\'||b.5.C==\'G\'||b.5.u==7||b.G<b.5.u)b.2k();b.1p();b.1L(\'2i\')};4.1L(\'2V\');6(!4.5.1O||a==I){4.t.y(4.E,p+\'S\');c()}10{8 o=!4.5.Y?{\'24\':p}:{\'21\':p};4.t.1g(o,4.5.1O,4.5.2b,c)}},2k:9(s){6(s!=K)4.5.1i=s;6(4.5.1i==0)z 4.1A();6(4.1d!=7)z;8 a=4;4.1d=2U(9(){a.16()},4.5.1i*2T)},1A:9(){6(4.1d==7)z;2S(4.1d);4.1d=7},1p:9(n,p){6(n==K||n==7){8 n=!4.P&&4.5.u!==0&&((4.5.C&&4.5.C!=\'A\')||4.5.u==7||4.G<4.5.u);6(!4.P&&(!4.5.C||4.5.C==\'A\')&&4.5.u!=7&&4.G>=4.5.u)n=4.M!=7&&!4.Z}6(p==K||p==7){8 p=!4.P&&4.5.u!==0&&((4.5.C&&4.5.C!=\'G\')||4.A>1);6(!4.P&&(!4.5.C||4.5.C==\'G\')&&4.5.u!=7&&4.A==1)p=4.M!=7&&4.Z}8 a=4;4.Q[n?\'1Y\':\'2h\'](4.5.2m,4.2r)[n?\'1x\':\'T\'](4.D(\'B-16-1t\')).1I(\'1t\',n?I:15);4.R[p?\'1Y\':\'2h\'](4.5.2j,4.2a)[p?\'1x\':\'T\'](4.D(\'B-11-1t\')).1I(\'1t\',p?I:15);6(4.Q.N>0&&(4.Q[0].1e==K||4.Q[0].1e!=n)&&4.5.1H!=7){4.Q.1c(9(){a.5.1H(a,4,n)});4.Q[0].1e=n}6(4.R.N>0&&(4.R[0].1e==K||4.R[0].1e!=p)&&4.5.1J!=7){4.R.1c(9(){a.5.1J(a,4,p)});4.R[0].1e=p}},1L:9(a){8 b=4.V==7?\'27\':(4.V<4.A?\'16\':\'11\');4.13(\'2y\',a,b);6(4.V!=4.A){4.13(\'2w\',a,b,4.A);4.13(\'2v\',a,b,4.V)}6(4.12!=4.G){4.13(\'2t\',a,b,4.G);4.13(\'2s\',a,b,4.12)}4.13(\'2q\',a,b,4.A,4.G,4.V,4.12);4.13(\'2p\',a,b,4.V,4.12,4.A,4.G)},13:9(a,b,c,d,e,f,g){6(4.5[a]==K||(1T 4.5[a]!=\'2n\'&&b!=\'2i\'))z;8 h=1T 4.5[a]==\'2n\'?4.5[a][b]:4.5[a];6(!$.2R(h))z;8 j=4;6(d===K)h(j,c,b);10 6(e===K)4.J(d).1c(9(){h(j,4,d,c,b)});10{1n(8 i=d;i<=e;i++)6(!(i>=f&&i<=g))4.J(i).1c(9(){h(j,4,i,c,b)})}},1B:9(i){z 4.1G(\'<1s></1s>\',i)},1G:9(e,i){8 a=$(e).T(4.D(\'B-1a\')).T(4.D(\'B-1a-\'+i));a.1I(\'2Q\',i);z a},D:9(c){z c+\' \'+c+(!4.5.Y?\'-2P\':\'-Y\')},U:9(e,d){8 a=e.2f!=K?e[0]:e;8 b=!4.5.Y?a.1v+r.W(a,\'2e\')+r.W(a,\'1j\'):a.2d+r.W(a,\'2c\')+r.W(a,\'1M\');6(d==K||b==d)z b;8 w=!4.5.Y?d-r.W(a,\'2e\')-r.W(a,\'1j\'):d-r.W(a,\'2c\')-r.W(a,\'1M\');$(a).y(4.O,w+\'S\');z 4.U(a)},1m:9(){z!4.5.Y?4.H[0].1v-r.L(4.H.y(\'2N\'))-r.L(4.H.y(\'2M\')):4.H[0].2d-r.L(4.H.y(\'2L\'))-r.L(4.H.y(\'2K\'))},2J:9(i,s){6(s==K)s=4.5.u;z 1l.3e((((i-1)/s)-1l.2I((i-1)/s))*s)+1}});r.19({2H:9(d){$.19(q,d)},W:9(e,p){6(!e)z 0;8 a=e.2f!=K?e[0]:e;6(p==\'1j\'&&$.2G.3i){8 b={\'1u\':\'1z\',\'2E\':\'2D\',\'1E\':\'1i\'},1Z,1X;$.29(a,b,9(){1Z=a.1v});b[\'1j\']=0;$.29(a,b,9(){1X=a.1v});z 1X-1Z}z r.L($.y(a,p))},L:9(v){v=2B(v);z 3p(v)?0:v}})})(3r);',62,214,'||||this|options|if|null|var|function||||||||||||||||||||list|size||||css|return|first|jcarousel|wrap|className|lt|container|last|clip|false|get|undefined|intval|tail|length|wh|locked|buttonNext|buttonPrev|px|addClass|dimension|prevFirst|margin|div|vertical|inTail|else|prev|prevLast|callback|animating|true|next|visible|scroll|extend|item|circular|each|timer|jcarouselstate|has|animate|initCallback|auto|marginRight|while|Math|clipping|for|parent|buttons|pos|before|li|disabled|display|offsetWidth|fn|removeClass|break|block|stopAuto|create|placeholder|reloadCallback|width|setup|format|buttonNextCallback|attr|buttonPrevCallback|ceil|notify|marginBottom|buttonPrevHTML|animation|buttonNextHTML|both|scrollTail|remove|typeof|after|old|offset|oWidth2|bind|oWidth|0px|top|empty|reset|left|height|start|init|reload|swap|funcPrev|easing|marginTop|offsetHeight|marginLeft|jquery|setHeight|unbind|onAfterAnimation|buttonPrevEvent|startAuto|click|buttonNextEvent|object|children|itemVisibleOutCallback|itemVisibleInCallback|funcNext|itemLastOutCallback|itemLastInCallback|prepend|itemFirstOutCallback|itemFirstInCallback|nodeName|itemLoadCallback|prototype|resize|parseInt|window|none|float|swing|browser|defaults|floor|index|borderBottomWidth|borderTopWidth|borderRightWidth|borderLeftWidth|normal|horizontal|jcarouselindex|isFunction|clearTimeout|1000|setTimeout|onBeforeAnimation|push|Aborting|ol|loop|infinite|ul|an|cause|will|This|items|set|No|jCarousel|skin|alert|indexOf|split|round|append|html|string|safari|new|parentNode|add|OL|UL|unlock|isNaN|lock|jQuery'.split('|'),0,{}))*/
/**
 * jCarousel - Riding carousels with jQuery
 *   http://sorgalla.com/jcarousel/
 *
 * Copyright (c) 2006 Jan Sorgalla (http://sorgalla.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Built on top of the jQuery library
 *   http://jquery.com
 *
 * Inspired by the "Carousel Component" by Bill Scott
 *   http://billwscott.com/carousel/
 */

(function($) {
    /**
     * Creates a carousel for all matched elements.
     *
     * @example $("#mycarousel").jcarousel();
     * @before <ul id="mycarousel"><li>First item</li><li>Second item</li></ul>
     * @result
     *
     * <div class="jcarousel-skin-name jcarousel-container">
     *   <div disabled="disabled" class="jcarousel-prev jcarousel-prev-disabled"></div>
     *   <div class="jcarousel-next"></div>
     *   <div class="jcarousel-clip">
     *     <ul class="jcarousel-list">
     *       <li class="jcarousel-item-1">First item</li>
     *       <li class="jcarousel-item-2">Second item</li>
     *     </ul>
     *   </div>
     * </div>
     *
     * @name jcarousel
     * @type jQuery
     * @param Hash o A set of key/value pairs to set as configuration properties.
     * @cat Plugins/jCarousel
     */
    $.fn.jcarousel = function(o) {
        return this.each(function() {
            new $jc(this, o);
        });
    };

    // Default configuration properties.
    var defaults = {
        vertical: false,
        start: 1,
        offset: 1,
        size: null,
        scroll: 3,
        visible: null,
        animation: 'normal',
        easing: 'swing',
        auto: 0,
        wrap: null,
        initCallback: null,
        reloadCallback: null,
        itemLoadCallback: null,
        itemFirstInCallback: null,
        itemFirstOutCallback: null,
        itemLastInCallback: null,
        itemLastOutCallback: null,
        itemVisibleInCallback: null,
        itemVisibleOutCallback: null,
        buttonNextHTML: '<div></div>',
        buttonPrevHTML: '<div></div>',
        buttonNextEvent: 'click',
        buttonPrevEvent: 'click',
        buttonNextCallback: null,
        buttonPrevCallback: null,
        setHeight: true
    };

    /**
     * The jCarousel object.
     *
     * @constructor
     * @name $.jcarousel
     * @param Object e The element to create the carousel for.
     * @param Hash o A set of key/value pairs to set as configuration properties.
     * @cat Plugins/jCarousel
     */
    $.jcarousel = function(e, o) {
        this.options    = $.extend({}, defaults, o || {});

        this.locked     = false;

        this.container  = null;
        this.clip       = null;
        this.list       = null;
        this.buttonNext = null;
        this.buttonPrev = null;

        this.wh = !this.options.vertical ? 'width' : 'height';
        this.lt = !this.options.vertical ? 'left' : 'top';

        if (e.nodeName == 'UL' || e.nodeName == 'OL') {
            this.list = $(e);
            this.container = this.list.parent();

            if ($.className.has(this.container[0].className, 'jcarousel-clip')) {
                if (!$.className.has(this.container[0].parentNode.className, 'jcarousel-container'))
                    this.container = this.container.wrap('<div></div>');

                this.container = this.container.parent();
            } else if (!$.className.has(this.container[0].className, 'jcarousel-container'))
                this.container = this.list.wrap('<div></div>').parent();

            // Move skin class over to container
            var split = e.className.split(' ');

            for (var i = 0; i < split.length; i++) {
                if (split[i].indexOf('jcarousel-skin') != -1) {
                    this.list.removeClass(split[i]);
                    this.container.addClass(split[i]);
                    //break; //Allow multiple skinclasses
                }
            }
        } else {
            this.container = $(e);
            this.list = $(e).children('ul,ol');
        }

        this.clip = this.list.parent();

        if (!this.clip.length || !$.className.has(this.clip[0].className, 'jcarousel-clip'))
            this.clip = this.list.wrap('<div></div>').parent();

        this.buttonPrev = $('.jcarousel-prev', this.container);

        if (this.buttonPrev.size() == 0 && this.options.buttonPrevHTML != null)
            this.buttonPrev = this.clip.before(this.options.buttonPrevHTML).prev();

        this.buttonPrev.addClass(this.className('jcarousel-prev'));

        this.buttonNext = $('.jcarousel-next', this.container);

        if (this.buttonNext.size() == 0 && this.options.buttonNextHTML != null)
            this.buttonNext = this.clip.before(this.options.buttonNextHTML).prev();

        this.buttonNext.addClass(this.className('jcarousel-next'));

        this.clip.addClass(this.className('jcarousel-clip'));
        this.list.addClass(this.className('jcarousel-list'));
        this.container.addClass(this.className('jcarousel-container'));

        var di = this.options.visible != null ? Math.ceil(this.clipping() / this.options.visible) : null;
        var li = this.list.children('li');

        var self = this;

        if (li.size() > 0) {
            var wh = 0, i = this.options.offset;
            li.each(function() {
                self.format(this, i++);
                wh += self.dimension(this, di);
            });
			
			if ( this.options.setHeight )
            	this.list.css(this.wh, wh + 'px');

            // Only set if not explicitly passed as option
            if (!o || o.size == undefined)
                this.options.size = li.size();
        }

        // For whatever reason, .show() does not work in Safari...
        this.container.css('display', 'block');
        this.buttonNext.css('display', 'block');
        this.buttonPrev.css('display', 'block');

        this.funcNext   = function() { self.next(); };
        this.funcPrev   = function() { self.prev(); };

        $(window).bind('resize', function() { self.reload(); });

        if (this.options.initCallback != null)
            this.options.initCallback(this, 'init');

        this.setup();
    };

    // Create shortcut for internal use
    var $jc = $.jcarousel;

    $jc.fn = $jc.prototype = {
        jcarousel: '0.2.2'
    };

    $jc.fn.extend = $jc.extend = $.extend;

    $jc.fn.extend({
        /**
         * Setups the carousel.
         *
         * @name setup
         * @type undefined
         * @cat Plugins/jCarousel
         */
        setup: function() {
            this.first     = null;
            this.last      = null;
            this.prevFirst = null;
            this.prevLast  = null;
            this.animating = false;
            this.timer     = null;
            this.tail      = null;
            this.inTail    = false;

            if (this.locked)
                return;

            this.list.css(this.lt, this.pos(this.options.offset) + 'px');
            var p = this.pos(this.options.start);
            this.prevFirst = this.prevLast = null;
            this.animate(p, false);
        },

        /**
         * Clears the list and resets the carousel.
         *
         * @name reset
         * @type undefined
         * @cat Plugins/jCarousel
         */
        reset: function() {
            this.list.empty();

            this.list.css(this.lt, '0px');
            this.list.css(this.wh, '0px');

            if (this.options.initCallback != null)
                this.options.initCallback(this, 'reset');

            this.setup();
        },

        /**
         * Reloads the carousel and adjusts positions.
         *
         * @name reload
         * @type undefined
         * @cat Plugins/jCarousel
         */
        reload: function() {
            if (this.tail != null && this.inTail)
                this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) + this.tail);

            this.tail   = null;
            this.inTail = false;

            if (this.options.reloadCallback != null)
                this.options.reloadCallback(this);

            if (this.options.visible != null) {
                var self = this;
                var di = Math.ceil(this.clipping() / this.options.visible), wh = 0, lt = 0;
                $('li', this.list).each(function(i) {
                    wh += self.dimension(this, di);
                    if (i + 1 < self.first)
                        lt = wh;
                });

                this.list.css(this.wh, wh + 'px');
                this.list.css(this.lt, -lt + 'px');
            }

            this.scroll(this.first, false);
        },

        /**
         * Locks the carousel.
         *
         * @name lock
         * @type undefined
         * @cat Plugins/jCarousel
         */
        lock: function() {
            this.locked = true;
            this.buttons();
        },

        /**
         * Unlocks the carousel.
         *
         * @name unlock
         * @type undefined
         * @cat Plugins/jCarousel
         */
        unlock: function() {
            this.locked = false;
            this.buttons();
        },

        /**
         * Sets the size of the carousel.
         *
         * @name size
         * @type undefined
         * @param Number s The size of the carousel.
         * @cat Plugins/jCarousel
         */
        size: function(s) {
            if (s != undefined) {
                this.options.size = s;
                if (!this.locked)
                    this.buttons();
            }

            return this.options.size;
        },

        /**
         * Checks whether a list element exists for the given index (or index range).
         *
         * @name get
         * @type bool
         * @param Number i The index of the (first) element.
         * @param Number i2 The index of the last element.
         * @cat Plugins/jCarousel
         */
        has: function(i, i2) {
            if (i2 == undefined || !i2)
                i2 = i;

            for (var j = i; j <= i2; j++) {
                var e = this.get(j).get(0);
                if (!e || $.className.has(e, 'jcarousel-item-placeholder'))
                    return false;
            }

            return true;
        },

        /**
         * Returns a jQuery object with list element for the given index.
         *
         * @name get
         * @type jQuery
         * @param Number i The index of the element.
         * @cat Plugins/jCarousel
         */
        get: function(i) {
            return $('.jcarousel-item-' + i, this.list);
        },

        /**
         * Adds an element for the given index to the list.
         * If the element already exists, it updates the inner html.
         * Returns the created element as jQuery object.
         *
         * @name add
         * @type jQuery
         * @param Number i The index of the element.
         * @param String s The innerHTML of the element.
         * @cat Plugins/jCarousel
         */
        add: function(i, s) {
            var e = this.get(i), old = 0;

            if (e.length == 0) {
                var c, e = this.create(i), j = $jc.intval(i);
                while (c = this.get(--j)) {
                    if (j <= 0 || c.length) {
                        j <= 0 ? this.list.prepend(e) : c.after(e);
                        break;
                    }
                }
            } else
                old = this.dimension(e);

            e.removeClass(this.className('jcarousel-item-placeholder'));
            typeof s == 'string' ? e.html(s) : e.empty().append(s);

            var di = this.options.visible != null ? Math.ceil(this.clipping() / this.options.visible) : null;
            var wh = this.dimension(e, di) - old;

            if (i > 0 && i < this.first)
                this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) + wh + 'px');

            this.list.css(this.wh, $jc.intval(this.list.css(this.wh)) + wh + 'px');

            return e;
        },

        /**
         * Removes an element for the given index from the list.
         *
         * @name remove
         * @type undefined
         * @param Number i The index of the element.
         * @cat Plugins/jCarousel
         */
        remove: function(i) {
            var e = this.get(i);

            // Check if item exists and is not currently visible
            if (!e.length || (i >= this.first && i <= this.last))
                return;

            var d = this.dimension(e);

            if (i < this.first)
                this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) + d + 'px');

            e.remove();

            this.list.css(this.wh, $jc.intval(this.list.css(this.wh)) - d + 'px');
        },

        /**
         * Moves the carousel forwards.
         *
         * @name next
         * @type undefined
         * @cat Plugins/jCarousel
         */
        next: function() {
            this.stopAuto();

            if (this.tail != null && !this.inTail)
                this.scrollTail(false);
            else
                this.scroll(((this.options.wrap == 'both' || this.options.wrap == 'last') && this.options.size != null && this.last == this.options.size) ? 1 : this.first + this.options.scroll);
        },

        /**
         * Moves the carousel backwards.
         *
         * @name prev
         * @type undefined
         * @cat Plugins/jCarousel
         */
        prev: function() {
            this.stopAuto();

            if (this.tail != null && this.inTail)
                this.scrollTail(true);
            else
                this.scroll(((this.options.wrap == 'both' || this.options.wrap == 'first') && this.options.size != null && this.first == 1) ? this.options.size : this.first - this.options.scroll);
        },

        /**
         * Scrolls the tail of the carousel.
         *
         * @name scrollTail
         * @type undefined
         * @param Bool b Whether scroll the tail back or forward.
         * @cat Plugins/jCarousel
         */
        scrollTail: function(b) {
            if (this.locked || this.animating || !this.tail)
                return;

            var pos  = $jc.intval(this.list.css(this.lt));

            !b ? pos -= this.tail : pos += this.tail;
            this.inTail = !b;

            // Save for callbacks
            this.prevFirst = this.first;
            this.prevLast  = this.last;

            this.animate(pos);
        },

        /**
         * Scrolls the carousel to a certain position.
         *
         * @name scroll
         * @type undefined
         * @param Number i The index of the element to scoll to.
         * @param Bool a Flag indicating whether to perform animation.
         * @cat Plugins/jCarousel
         */
        scroll: function(i, a) {
            if (this.locked || this.animating)
                return;

            this.animate(this.pos(i), a);
        },

        /**
         * Prepares the carousel and return the position for a certian index.
         *
         * @name pos
         * @type Number
         * @param Number i The index of the element to scoll to.
         * @cat Plugins/jCarousel
         */
        pos: function(i) {
            if (this.locked || this.animating)
                return;

            if (this.options.wrap != 'circular')
                i = i < 1 ? 1 : (this.options.size && i > this.options.size ? this.options.size : i);

            var back = this.first > i;
            var pos  = $jc.intval(this.list.css(this.lt));

            // Create placeholders, new list width/height
            // and new list position
            var f = this.options.wrap != 'circular' && this.first <= 1 ? 1 : this.first;
            var c = back ? this.get(f) : this.get(this.last);
            var j = back ? f : f - 1;
            var e = null, l = 0, p = false, d = 0;

            while (back ? --j >= i : ++j < i) {
                e = this.get(j);
                p = !e.length;
                if (e.length == 0) {
                    e = this.create(j).addClass(this.className('jcarousel-item-placeholder'));
                    c[back ? 'before' : 'after' ](e);
                }

                c = e;
                d = this.dimension(e);

                if (p)
                    l += d;

                if (this.first != null && (this.options.wrap == 'circular' || (j >= 1 && (this.options.size == null || j <= this.options.size))))
                    pos = back ? pos + d : pos - d;
            }

            // Calculate visible items
            var clipping = this.clipping();
            var cache = [];
            var visible = 0, j = i, v = 0;
            var c = this.get(i - 1);

            while (++visible) {
                e = this.get(j);
                p = !e.length;
                if (e.length == 0) {
                    e = this.create(j).addClass(this.className('jcarousel-item-placeholder'));
                    // This should only happen on a next scroll
                    c.length == 0 ? this.list.prepend(e) : c[back ? 'before' : 'after' ](e);
                }

                c = e;
                var d = this.dimension(e);

                if (d == 0) {
                    alert('jCarousel: No width/height set for items. This will cause an infinite loop. Aborting...');
                    return 0;
                }

                if (this.options.wrap != 'circular' && this.options.size !== null && j > this.options.size)
                    cache.push(e);
                else if (p)
                    l += d;

                v += d;

                if (v >= clipping)
                    break;

                j++;
            }

             // Remove out-of-range placeholders
            for (var x = 0; x < cache.length; x++)
                cache[x].remove();

            // Resize list
            if (l > 0) {
                this.list.css(this.wh, this.dimension(this.list) + l + 'px');

                if (back) {
                    pos -= l;
                    this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) - l + 'px');
                }
            }

            // Calculate first and last item
            var last = i + visible - 1;
            if (this.options.wrap != 'circular' && this.options.size && last > this.options.size)
                last = this.options.size;

            if (j > last) {
                visible = 0, j = last, v = 0;
                while (++visible) {
                    var e = this.get(j--);
                    if (!e.length)
                        break;
                    v += this.dimension(e);
                    if (v >= clipping)
                        break;
                }
            }

            var first = last - visible + 1;
            if (this.options.wrap != 'circular' && first < 1)
                first = 1;

            if (this.inTail && back) {
                pos += this.tail;
                this.inTail = false;
            }

            this.tail = null;
            if (this.options.wrap != 'circular' && last == this.options.size && (last - visible + 1) >= 1) {
                var m = $jc.margin(this.get(last), !this.options.vertical ? 'marginRight' : 'marginBottom');
                if ((v - m) > clipping)
                    this.tail = v - clipping - m;
            }

            // Adjust position
            while (i-- > first)
                pos += this.dimension(this.get(i));

            // Save visible item range
            this.prevFirst = this.first;
            this.prevLast  = this.last;
            this.first     = first;
            this.last      = last;

            return pos;
        },

        /**
         * Animates the carousel to a certain position.
         *
         * @name animate
         * @type undefined
         * @param mixed p Position to scroll to.
         * @param Bool a Flag indicating whether to perform animation.
         * @cat Plugins/jCarousel
         */
        animate: function(p, a) {
            if (this.locked || this.animating)
                return;

            this.animating = true;

            var self = this;
            var scrolled = function() {
                self.animating = false;

                if (p == 0)
                    self.list.css(self.lt,  0);

                if (self.options.wrap == 'both' || self.options.wrap == 'last' || self.options.size == null || self.last < self.options.size)
                    self.startAuto();

                self.buttons();
                self.notify('onAfterAnimation');
            };

            this.notify('onBeforeAnimation');

            // Animate
            if (!this.options.animation || a == false) {
                this.list.css(this.lt, p + 'px');
                scrolled();
            } else {
                var o = !this.options.vertical ? {'left': p} : {'top': p};
                this.list.animate(o, this.options.animation, this.options.easing, scrolled);
            }
        },

        /**
         * Starts autoscrolling.
         *
         * @name auto
         * @type undefined
         * @param Number s Seconds to periodically autoscroll the content.
         * @cat Plugins/jCarousel
         */
        startAuto: function(s) {
            if (s != undefined)
                this.options.auto = s;

            if (this.options.auto == 0)
                return this.stopAuto();

            if (this.timer != null)
                return;

            var self = this;
            this.timer = setTimeout(function() { self.next(); }, this.options.auto * 1000);
        },

        /**
         * Stops autoscrolling.
         *
         * @name stopAuto
         * @type undefined
         * @cat Plugins/jCarousel
         */
        stopAuto: function() {
            if (this.timer == null)
                return;

            clearTimeout(this.timer);
            this.timer = null;
        },

        /**
         * Sets the states of the prev/next buttons.
         *
         * @name buttons
         * @type undefined
         * @cat Plugins/jCarousel
         */
        buttons: function(n, p) {
            if (n == undefined || n == null) {
                var n = !this.locked && this.options.size !== 0 && ((this.options.wrap && this.options.wrap != 'first') || this.options.size == null || this.last < this.options.size);
                if (!this.locked && (!this.options.wrap || this.options.wrap == 'first') && this.options.size != null && this.last >= this.options.size)
                    n = this.tail != null && !this.inTail;
            }

            if (p == undefined || p == null) {
                var p = !this.locked && this.options.size !== 0 && ((this.options.wrap && this.options.wrap != 'last') || this.first > 1);
                if (!this.locked && (!this.options.wrap || this.options.wrap == 'last') && this.options.size != null && this.first == 1)
                    p = this.tail != null && this.inTail;
            }

            var self = this;

            this.buttonNext[n ? 'bind' : 'unbind'](this.options.buttonNextEvent, this.funcNext)[n ? 'removeClass' : 'addClass'](this.className('jcarousel-next-disabled')).attr('disabled', n ? false : true);
            this.buttonPrev[p ? 'bind' : 'unbind'](this.options.buttonPrevEvent, this.funcPrev)[p ? 'removeClass' : 'addClass'](this.className('jcarousel-prev-disabled')).attr('disabled', p ? false : true);

            if (this.buttonNext.length > 0 && (this.buttonNext[0].jcarouselstate == undefined || this.buttonNext[0].jcarouselstate != n) && this.options.buttonNextCallback != null) {
                this.buttonNext.each(function() { self.options.buttonNextCallback(self, this, n); });
                this.buttonNext[0].jcarouselstate = n;
            }

            if (this.buttonPrev.length > 0 && (this.buttonPrev[0].jcarouselstate == undefined || this.buttonPrev[0].jcarouselstate != p) && this.options.buttonPrevCallback != null) {
                this.buttonPrev.each(function() { self.options.buttonPrevCallback(self, this, p); });
                this.buttonPrev[0].jcarouselstate = p;
            }
        },

        notify: function(evt) {
            var state = this.prevFirst == null ? 'init' : (this.prevFirst < this.first ? 'next' : 'prev');

            // Load items
            this.callback('itemLoadCallback', evt, state);

            if (this.prevFirst != this.first) {
                this.callback('itemFirstInCallback', evt, state, this.first);
                this.callback('itemFirstOutCallback', evt, state, this.prevFirst);
            }

            if (this.prevLast != this.last) {
                this.callback('itemLastInCallback', evt, state, this.last);
                this.callback('itemLastOutCallback', evt, state, this.prevLast);
            }

            this.callback('itemVisibleInCallback', evt, state, this.first, this.last, this.prevFirst, this.prevLast);
            this.callback('itemVisibleOutCallback', evt, state, this.prevFirst, this.prevLast, this.first, this.last);
        },

        callback: function(cb, evt, state, i1, i2, i3, i4) {
            if (this.options[cb] == undefined || (typeof this.options[cb] != 'object' && evt != 'onAfterAnimation'))
                return;

            var callback = typeof this.options[cb] == 'object' ? this.options[cb][evt] : this.options[cb];

            if (!$.isFunction(callback))
                return;

            var self = this;

            if (i1 === undefined)
                callback(self, state, evt);
            else if (i2 === undefined)
                this.get(i1).each(function() { callback(self, this, i1, state, evt); });
            else {
                for (var i = i1; i <= i2; i++)
                    if (!(i >= i3 && i <= i4))
                        this.get(i).each(function() { callback(self, this, i, state, evt); });
            }
        },

        create: function(i) {
            return this.format('<li></li>', i);
        },

        format: function(e, i) {
            var $e = $(e).addClass(this.className('jcarousel-item')).addClass(this.className('jcarousel-item-' + i));
            $e.attr('jcarouselindex', i);
            return $e;
        },

        className: function(c) {
            return c + ' ' + c + (!this.options.vertical ? '-horizontal' : '-vertical');
        },

        dimension: function(e, d) {
            var el = e.jquery != undefined ? e[0] : e;

            var old = !this.options.vertical ?
                el.offsetWidth + $jc.margin(el, 'marginLeft') + $jc.margin(el, 'marginRight') :
                el.offsetHeight + $jc.margin(el, 'marginTop') + $jc.margin(el, 'marginBottom');

            if (d == undefined || old == d)
                return old;

            var w = !this.options.vertical ?
                d - $jc.margin(el, 'marginLeft') - $jc.margin(el, 'marginRight') :
                d - $jc.margin(el, 'marginTop') - $jc.margin(el, 'marginBottom');

            if ( this.options.setHeight )
				$(el).css(this.wh, w + 'px');

            return this.dimension(el);
        },

        clipping: function() {
            return !this.options.vertical ?
                this.clip[0].offsetWidth - $jc.intval(this.clip.css('borderLeftWidth')) - $jc.intval(this.clip.css('borderRightWidth')) :
                this.clip[0].offsetHeight - $jc.intval(this.clip.css('borderTopWidth')) - $jc.intval(this.clip.css('borderBottomWidth'));
        },

        index: function(i, s) {
            if (s == undefined)
                s = this.options.size;

            return Math.round((((i-1) / s) - Math.floor((i-1) / s)) * s) + 1;
        }
    });

    $jc.extend({
        /**
         * Sets the global default configuration properties.
         *
         * @name defaults
         * @descr Sets the global default configuration properties.
         * @type undefined
         * @param Hash d A set of key/value pairs to set as configuration properties.
         * @cat Plugins/jCarousel
         */
        defaults: function(d) {
            $.extend(defaults, d);
        },

        margin: function(e, p) {
            if (!e)
                return 0;

            var el = e.jquery != undefined ? e[0] : e;

            if (p == 'marginRight' && $.browser.safari) {
                var old = {'display': 'block', 'float': 'none', 'width': 'auto'}, oWidth, oWidth2;

                $.swap(el, old, function() { oWidth = el.offsetWidth; });

                old['marginRight'] = 0;
                $.swap(el, old, function() { oWidth2 = el.offsetWidth; });

                return oWidth2 - oWidth;
            }

            return $jc.intval($.css(el, p));
        },

        intval: function(v) {
            v = parseInt(v);
            return isNaN(v) ? 0 : v;
        }
    });

})(jQuery);
