
/*
	Kwicks for jQuery (version 1.5.1)
	Copyright (c) 2008 Jeremy Martin
	http://www.jeremymartin.name/projects.php?project=kwicks
	
	Licensed under the MIT license:
		http://www.opensource.org/licenses/mit-license.php

	Any and all use of this script must be accompanied by this copyright/license notice in its present form.
*/
(function($){$.fn.kwicks=function(n){var p={isVertical:false,sticky:false,defaultKwick:0,event:'mouseover',spacing:0,duration:500};var o=$.extend(p,n);var q=(o.isVertical?'height':'width');var r=(o.isVertical?'top':'left');return this.each(function(){container=$(this);var k=container.children('li');var l=k.eq(0).css(q).replace(/px/,'');if(!o.max){o.max=(l*k.size())-(o.min*(k.size()-1))}else{o.min=((l*k.size())-o.max)/(k.size()-1)}if(o.isVertical){container.css({width:k.eq(0).css('width'),height:(l*k.size())+(o.spacing*(k.size()-1))+'px'})}else{container.css({width:(l*k.size())+(o.spacing*(k.size()-1))+'px',height:k.eq(0).css('height')})}var m=[];for(i=0;i<k.size();i++){m[i]=[];for(j=1;j<k.size()-1;j++){if(i==j){m[i][j]=o.isVertical?j*o.min+(j*o.spacing):j*o.min+(j*o.spacing)}else{m[i][j]=(j<=i?(j*o.min):(j-1)*o.min+o.max)+(j*o.spacing)}}}k.each(function(i){var h=$(this);if(i===0){h.css(r,'0px')}else if(i==k.size()-1){h.css(o.isVertical?'bottom':'right','0px')}else{if(o.sticky){h.css(r,m[o.defaultKwick][i])}else{h.css(r,(i*l)+(i*o.spacing))}}if(o.sticky){if(o.defaultKwick==i){h.css(q,o.max+'px');h.addClass('active')}else{h.css(q,o.min+'px')}}h.css({margin:0,position:'absolute'});h.bind(o.event,function(){var c=[];var d=[];k.stop().removeClass('active');for(j=0;j<k.size();j++){c[j]=k.eq(j).css(q).replace(/px/,'');d[j]=k.eq(j).css(r).replace(/px/,'')}var e={};e[q]=o.max;var f=o.max-c[i];var g=c[i]/f;h.addClass('active').animate(e,{step:function(a){var b=f!=0?a/f-g:1;k.each(function(j){if(j!=i){k.eq(j).css(q,c[j]-((c[j]-o.min)*b)+'px')}if(j>0&&j<k.size()-1){k.eq(j).css(r,d[j]-((d[j]-m[i][j])*b)+'px')}})},duration:o.duration,easing:o.easing})})});if(!o.sticky){container.bind("mouseleave",function(){var c=[];var d=[];k.removeClass('active').stop();for(i=0;i<k.size();i++){c[i]=k.eq(i).css(q).replace(/px/,'');d[i]=k.eq(i).css(r).replace(/px/,'')}var e={};e[q]=l;var f=l-c[0];k.eq(0).animate(e,{step:function(a){var b=f!=0?(a-c[0])/f:1;for(i=1;i<k.size();i++){k.eq(i).css(q,c[i]-((c[i]-l)*b)+'px');if(i<k.size()-1){k.eq(i).css(r,d[i]-((d[i]-((i*l)+(i*o.spacing)))*b)+'px')}}},duration:o.duration,easing:o.easing})})}})}})(jQuery);
/* ------------------------------------------------------------------------
	s3Slider
	
	Developped By: Boban Karišik -> http://www.serie3.info/
        CSS Help: Mészáros Róbert -> http://www.perspectived.com/
	Version: 1.0
	
	Copyright: Feel free to redistribute the script/modify it, as
			   long as you leave my infos at the top.
------------------------------------------------------------------------- */


(function($){  

    $.fn.s3Slider = function(vars) {       
        
        var element     = this;
        var timeOut     = (vars.timeOut != undefined) ? vars.timeOut : 4000;
        var current     = null;
        var timeOutFn   = null;
        var faderStat   = true;
        var mOver       = false;
        var items       = $("#" + element[0].id + "Content ." + element[0].id + "Image");
        var itemsSpan   = $("#" + element[0].id + "Content ." + element[0].id + "Image span");
            
        items.each(function(i) {
    
            $(items[i]).mouseover(function() {
               mOver = true;
            });
            
            $(items[i]).mouseout(function() {
                mOver   = false;
                fadeElement(true);
            });
            
        });
        
        var fadeElement = function(isMouseOut) {
            var thisTimeOut = (isMouseOut) ? (timeOut/2) : timeOut;
            thisTimeOut = (faderStat) ? 10 : thisTimeOut;
            if(items.length > 0) {
                timeOutFn = setTimeout(makeSlider, thisTimeOut);
            } else {
                console.log("Poof..");
            }
        }
        
        var makeSlider = function() {
            current = (current != null) ? current : items[(items.length-1)];
            var currNo      = jQuery.inArray(current, items) + 1
            currNo = (currNo == items.length) ? 0 : (currNo - 1);
            var newMargin   = $(element).width() * currNo;
            if(faderStat == true) {
                if(!mOver) {
                    $(items[currNo]).fadeIn((timeOut/6), function() {
                        if($(itemsSpan[currNo]).css('bottom') == 0) {
                            $(itemsSpan[currNo]).slideUp((timeOut/6), function() {
                                faderStat = false;
                                current = items[currNo];
                                if(!mOver) {
                                    fadeElement(false);
                                }
                            });
                        } else {
                            $(itemsSpan[currNo]).slideDown((timeOut/6), function() {
                                faderStat = false;
                                current = items[currNo];
                                if(!mOver) {
                                    fadeElement(false);
                                }
                            });
                        }
                    });
                }
            } else {
                if(!mOver) {
                    if($(itemsSpan[currNo]).css('bottom') == 0) {
                        $(itemsSpan[currNo]).slideDown((timeOut/6), function() {
                            $(items[currNo]).fadeOut((timeOut/6), function() {
                                faderStat = true;
                                current = items[(currNo+1)];
                                if(!mOver) {
                                    fadeElement(false);
                                }
                            });
                        });
                    } else {
                        $(itemsSpan[currNo]).slideUp((timeOut/6), function() {
                        $(items[currNo]).fadeOut((timeOut/6), function() {
                                faderStat = true;
                                current = items[(currNo+1)];
                                if(!mOver) {
                                    fadeElement(false);
                                }
                            });
                        });
                    }
                }
            }
        }
        
        makeSlider();

    };  

})(jQuery);

/*******************************************************************************
 jquery.mb.components
 Copyright (c) 2001-2010. Matteo Bicocchi (Pupunzi); Open lab srl, Firenze - Italy
 email: info@pupunzi.com
 site: http://pupunzi.com

 Licences: MIT, GPL
 http://www.opensource.org/licenses/mit-license.php
 http://www.gnu.org/licenses/gpl.html
 ******************************************************************************/

/*
 * Name:jquery.mb.scrollable
 * Version: 1.5.7
 */

(function($) {
  $.mbScrollable= {
    plugin:"mb.scrollable",
    author:"MB",
    version:"1.5.7",
    defaults:{
      dir:"horizontal",
      width:950,
      elementsInPage:4,
      elementMargin:2,
      shadow:false,
      height:"auto",
      controls:"#controls",
      slideTimer:600,
      autoscroll:false,
      scrollTimer:6000,

      nextCallback:function(){},
      prevCallback:function(){}
    },

    buildMbScrollable: function(options){
      return this.each (function (){
        this.options = {};
        $.extend (this.options, $.mbScrollable.defaults);
        $.extend (this.options, options);

        var mbScrollable=this;
        mbScrollable.isVertical= mbScrollable.options.dir!="horizontal";
        var controls=$(mbScrollable.options.controls);
        mbScrollable.idx=1;
        mbScrollable.scrollTo=0;
        mbScrollable.elements= $(mbScrollable).children();
        mbScrollable.elements.addClass("scrollEl");
        controls.hide();

        $(mbScrollable).children().each(function(){$(this).wrap("<div class='SECont'></div>");});
        if (mbScrollable.options.shadow){
          $(mbScrollable.elements).css("-moz-box-shadow",mbScrollable.options.shadow);
          $(mbScrollable.elements).css("-webkit-box-shadow",mbScrollable.options.shadow);
        }
        mbScrollable.elements= $(mbScrollable).children();
        var eip= mbScrollable.options.elementsInPage<this.elements.size()?mbScrollable.options.elementsInPage:mbScrollable.elements.size();
        if(mbScrollable.isVertical){
          mbScrollable.singleElDim= (mbScrollable.options.height/eip)-mbScrollable.options.elementMargin;
          $(mbScrollable.elements).css({marginBottom:mbScrollable.options.elementMargin, height:mbScrollable.singleElDim, width:mbScrollable.options.width});
        }else{
          mbScrollable.singleElDim= (mbScrollable.options.width/eip)-mbScrollable.options.elementMargin;
          $(mbScrollable.elements).css({marginRight:mbScrollable.options.elementMargin, width:mbScrollable.singleElDim, display:"inline-block",float:"left" }); //float:"left"
        }
        this.elementsDim= (mbScrollable.singleElDim*mbScrollable.elements.size())+(mbScrollable.options.elementMargin*mbScrollable.elements.size());
        mbScrollable.totalPages= Math.ceil(mbScrollable.elements.size()/mbScrollable.options.elementsInPage);

        var adj= $.browser.safari && mbScrollable.options.elementsInPage>2?mbScrollable.options.elementMargin/(mbScrollable.options.elementsInPage):0;

        if(mbScrollable.isVertical)
          $(mbScrollable).css({overflow:"hidden", height:mbScrollable.options.height-adj,width:mbScrollable.options.width, paddingRight:5, position:"relative"});
        else
          $(mbScrollable).css({overflow:"hidden", width:mbScrollable.options.width-adj,height:mbScrollable.options.height,paddingBottom:5, position:"relative"});

        var mbscrollableStrip=$("<div class='scrollableStrip'/>").css({width:mbScrollable.elementsDim, position:"relative"});
        $(mbScrollable.elements).wrapAll(mbscrollableStrip);
        mbScrollable.mbscrollableStrip=$(mbScrollable).find(".scrollableStrip");
        $(mbScrollable.elements).hover(
                function(){
                  //                  console.debug(mbScrollable.autoScrollActive);
                  if(mbScrollable.autoScrollActive)
                    $(mbScrollable).mbStopAutoscroll();
                },
                function(){
                  if(mbScrollable.autoScrollActive)
                    $(mbScrollable).mbAutoscroll();
                });
        if(mbScrollable.options.autoscroll && mbScrollable.elements.size()>mbScrollable.options.elementsInPage){
          mbScrollable.autoScrollActive=true;
          $(mbScrollable).mbAutoscroll();
        }
        $(mbScrollable).mbPageIndex();
        $(mbScrollable).mbActivateControls();
        setTimeout(function(){
          $(".scrollEl").fadeIn();
        },1000);
        $(mbScrollable).mbManageControls();
      });
    },

    mbNextPage: function(auto){
      var mbScrollable= $(this).get(0);
      if (!auto) mbScrollable.autoScrollActive=false;

      if(mbScrollable.idx==mbScrollable.totalPages){
        $(mbScrollable).mbManageControls();
        return;
      }
      if (mbScrollable.options.nextCallback) mbScrollable.options.nextCallback();
      var adj=  $.browser.safari && mbScrollable.options.elementsInPage>2?mbScrollable.options.elementMargin/mbScrollable.options.elementsInPage:0;
      mbScrollable.scrollTo-=((mbScrollable.singleElDim+mbScrollable.options.elementMargin)*mbScrollable.options.elementsInPage)-adj;
      if (mbScrollable.isVertical){
        if ((mbScrollable.scrollTo<-mbScrollable.elementsDim+mbScrollable.options.height))
          mbScrollable.scrollTo=-mbScrollable.elementsDim+mbScrollable.options.height;
        $(mbScrollable.mbscrollableStrip).animate({marginTop:mbScrollable.scrollTo},mbScrollable.options.slideTimer);
      }else{
        if ((mbScrollable.scrollTo<-mbScrollable.elementsDim+mbScrollable.options.width))
          mbScrollable.scrollTo=-mbScrollable.elementsDim+mbScrollable.options.width;
        $(mbScrollable.mbscrollableStrip).animate({marginLeft:mbScrollable.scrollTo},mbScrollable.options.slideTimer);
      }
      mbScrollable.idx+=1;
      $(this).mbManageControls();
    },

    mbPrevPage: function(auto){
      var mbScrollable= $(this).get(0);
      if (!auto) mbScrollable.autoScrollActive=false;

      if(mbScrollable.idx==1){
        $(mbScrollable).mbManageControls();
        return;
      }

      if (mbScrollable.options.prevCallback) mbScrollable.options.prevCallback();

      var adj=  $.browser.safari && mbScrollable.options.elementsInPage>2?mbScrollable.options.elementMargin/mbScrollable.options.elementsInPage:0;
      mbScrollable.scrollTo+=((mbScrollable.singleElDim+mbScrollable.options.elementMargin)*mbScrollable.options.elementsInPage)+adj;

      if (mbScrollable.isVertical){
        if (mbScrollable.scrollTo>=0) mbScrollable.scrollTo=0;
        $(mbScrollable.mbscrollableStrip).animate({marginTop:mbScrollable.scrollTo},mbScrollable.options.slideTimer);
      }else{
        if (mbScrollable.scrollTo>=0) mbScrollable.scrollTo=0;
        $(mbScrollable.mbscrollableStrip).animate({marginLeft:mbScrollable.scrollTo},mbScrollable.options.slideTimer);
      }
      mbScrollable.idx-=1;
      $(this).mbManageControls();
    },

    mbFirstPage: function(){
      var mbScrollable= $(this).get(0);
      mbScrollable.autoScrollActive=false;

      mbScrollable.scrollTo=0;
      if (mbScrollable.isVertical){
        $(mbScrollable.mbscrollableStrip).animate({marginTop:mbScrollable.scrollTo},mbScrollable.options.slideTimer);
      }else{
        $(mbScrollable.mbscrollableStrip).animate({marginLeft:mbScrollable.scrollTo},mbScrollable.options.slideTimer);
      }
      mbScrollable.idx=1;
      $(this).mbManageControls();
      $(mbScrollable).mbStopAutoscroll();
    },

    mbLastPage: function(){
      var mbScrollable= $(this).get(0);
      mbScrollable.autoScrollActive=false;

      if (mbScrollable.isVertical){
        mbScrollable.scrollTo=-mbScrollable.elementsDim+mbScrollable.options.height;
        $(mbScrollable.mbscrollableStrip).animate({marginTop:mbScrollable.scrollTo},mbScrollable.options.slideTimer);
      }else{
        mbScrollable.scrollTo=-mbScrollable.elementsDim+mbScrollable.options.width;
        $(mbScrollable.mbscrollableStrip).animate({marginLeft:mbScrollable.scrollTo},mbScrollable.options.slideTimer);
      }
      mbScrollable.idx=mbScrollable.totalPages;
      $(mbScrollable).mbManageControls();
      $(mbScrollable).mbStopAutoscroll();
    },

    mbPageIndex: function(){
      var mbScrollable= $(this).get(0);
      var controls=$(mbScrollable.options.controls);
      var pages=controls.find(".pageIndex");
      if (pages){
        function getPage(i){
          mbScrollable.scrollTo=-((mbScrollable.singleElDim+mbScrollable.options.elementMargin)*(mbScrollable.options.elementsInPage*(i-1)));
          if(mbScrollable.isVertical){
            if (mbScrollable.scrollTo<-mbScrollable.elementsDim+mbScrollable.options.height)
              mbScrollable.scrollTo=-mbScrollable.elementsDim+mbScrollable.options.height;
            $(mbScrollable.mbscrollableStrip).animate({marginTop:mbScrollable.scrollTo},mbScrollable.options.slideTimer);
          }else{
            if (mbScrollable.scrollTo<-mbScrollable.elementsDim+mbScrollable.options.width)
              mbScrollable.scrollTo=-mbScrollable.elementsDim+mbScrollable.options.width;
            $(mbScrollable.mbscrollableStrip).animate({marginLeft:mbScrollable.scrollTo},mbScrollable.options.slideTimer);
          }
          mbScrollable.idx = Math.floor(i);
          $(mbScrollable).mbManageControls();
        }
        var n=0;
        for(var i=1;i<=mbScrollable.totalPages;i++){
          n++;
          var p=$("<span class='page'> "+n+" <\/span>").bind("click",function(){
            getPage($(this).html());
            $(mbScrollable).mbStopAutoscroll();
            mbScrollable.autoScrollActive=false;
          });
          pages.append(p);
        };
      }
    },
    mbAutoscroll:function(){
      var dir= "next";
      var mbScrollable= $(this).get(0);
      mbScrollable.autoScrollActive=true;

      if(mbScrollable.autoscroll) return;
      var timer=mbScrollable.options.scrollTimer+mbScrollable.options.slideTimer;
      mbScrollable.autoscroll = true;
      mbScrollable.auto = setInterval(function(){
        dir= mbScrollable.idx==1?"next":mbScrollable.idx==mbScrollable.totalPages?"prev":dir;
        if(dir=="next")
          $(mbScrollable).mbNextPage(true);
        else
          $(mbScrollable).mbPrevPage(true);
      },timer);
      $(mbScrollable).mbManageControls();
    },

    mbStopAutoscroll: function(){
      var mbScrollable= $(this).get(0);
      mbScrollable.autoscroll = false;
      clearInterval(mbScrollable.auto);
      $(mbScrollable).mbManageControls();

    },

    mbActivateControls: function(){
      var mbScrollable=$(this).get(0);
      var controls=$(mbScrollable.options.controls);
      controls.find(".first").bind("click",function(){$(mbScrollable).mbFirstPage();});
      controls.find(".prev").bind("click",function(){$(mbScrollable).mbStopAutoscroll();$(mbScrollable).mbPrevPage();});
      controls.find(".next").bind("click",function(){$(mbScrollable).mbStopAutoscroll();$(mbScrollable).mbNextPage();});
      controls.find(".last").bind("click",function(){$(mbScrollable).mbLastPage();});
      controls.find(".start").bind("click",function(){$(mbScrollable).mbAutoscroll();});
      controls.find(".stop").bind("click",function(){$(mbScrollable).mbStopAutoscroll();mbScrollable.autoScrollActive=false;});
    },

    mbManageControls: function(){
      var mbScrollable=$(this).get(0);
      var controls=$(mbScrollable.options.controls);
      if (mbScrollable.elements.size()<=mbScrollable.options.elementsInPage){
        controls.hide();
      }else{
        controls.fadeIn();
      }
      if (mbScrollable.idx==mbScrollable.totalPages){
        controls.find(".last").addClass("disabled");
        controls.find(".next").addClass("disabled");
      }else{
        controls.find(".last").removeClass("disabled");
        controls.find(".next").removeClass("disabled");
      }

      if (mbScrollable.idx==1){
        controls.find(".first").addClass("disabled");
        controls.find(".prev").addClass("disabled");
      }else{
        controls.find(".first").removeClass("disabled");
        controls.find(".prev").removeClass("disabled");
      }

      if (mbScrollable.autoscroll){
        controls.find(".start").addClass("sel");
        controls.find(".stop").removeClass("sel");
      }else{
        controls.find(".start").removeClass("sel");
        controls.find(".stop").addClass("sel");
      }
      controls.find(".page").removeClass("sel");
      controls.find(".page").eq(mbScrollable.idx-1).addClass("sel");
      controls.find(".idx").html(mbScrollable.idx+" / "+mbScrollable.totalPages);
    },

    goToPage: function(i,hasAnim) {
      var mbScrollable= $(this).get(0);
      var anim= hasAnim?0:mbScrollable.options.slideTimer;
      if (i>mbScrollable.totalPages) i=mbScrollable.totalPages;
      mbScrollable.scrollTo=-((mbScrollable.singleElDim+mbScrollable.options.elementMargin)*(mbScrollable.options.elementsInPage*(i-1)));
      if(mbScrollable.isVertical){
        if (mbScrollable.scrollTo<-mbScrollable.elementsDim+mbScrollable.options.height)
          mbScrollable.scrollTo=-mbScrollable.elementsDim+mbScrollable.options.height;
        $(mbScrollable.mbscrollableStrip).animate({marginTop:mbScrollable.scrollTo},anim);
      }else{
        if (mbScrollable.scrollTo<-mbScrollable.elementsDim+mbScrollable.options.width)
          mbScrollable.scrollTo=-mbScrollable.elementsDim+mbScrollable.options.width;
        $(mbScrollable.mbscrollableStrip).animate({marginLeft:mbScrollable.scrollTo},anim);
      }
      mbScrollable.idx = Math.floor(i);
      $(mbScrollable).mbManageControls();
      $(mbScrollable).mbStopAutoscroll();
      mbScrollable.autoScrollActive=false;
    }
/*
    //WIP 1.6.0
    mbAddElement: function(n){
      var mbScrollable=$(this).get(0);
      var newEl=$(n);
      newEl.addClass("scrollEl");

      $(mbScrollable).find(".scrollableStrip").append(newEl);
      newEl.wrap("<div class='SECont'/>");
      newEl.css({marginRight:mbScrollable.options.elementMargin, width:mbScrollable.singleElDim});
    }
*/
  };

  $.fn.mbScrollable=$.mbScrollable.buildMbScrollable;
  $.fn.mbNextPage=$.mbScrollable.mbNextPage;
  $.fn.mbPrevPage=$.mbScrollable.mbPrevPage;
  $.fn.mbFirstPage=$.mbScrollable.mbFirstPage;
  $.fn.mbLastPage=$.mbScrollable.mbLastPage;
  $.fn.mbPageIndex=$.mbScrollable.mbPageIndex;
  $.fn.mbgotoPage=$.mbScrollable.gotoPage;
  $.fn.mbAutoscroll=$.mbScrollable.mbAutoscroll;
  $.fn.mbStopAutoscroll=$.mbScrollable.mbStopAutoscroll;
  $.fn.mbActivateControls=$.mbScrollable.mbActivateControls;
  $.fn.mbManageControls=$.mbScrollable.mbManageControls;
  $.fn.goToPage=$.mbScrollable.goToPage;

//  $.fn.mbAddElement=$.mbScrollable.mbAddElement;

})(jQuery);

/*!
 * jQuery hashchange event - v1.3 - 7/21/2010
 * http://benalman.com/projects/jquery-hashchange-plugin/
 * 
 * Copyright (c) 2010 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
 */

// Script: jQuery hashchange event
//
// *Version: 1.3, Last updated: 7/21/2010*
// 
// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
// GitHub       - http://github.com/cowboy/jquery-hashchange/
// Source       - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
// (Minified)   - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
// 
// About: License
// 
// Copyright (c) 2010 "Cowboy" Ben Alman,
// Dual licensed under the MIT and GPL licenses.
// http://benalman.com/about/license/
// 
// About: Examples
// 
// These working examples, complete with fully commented code, illustrate a few
// ways in which this plugin can be used.
// 
// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
// 
// About: Support and Testing
// 
// Information about what version or versions of jQuery this plugin has been
// tested with, what browsers it has been tested in, and where the unit tests
// reside (so you can test it yourself).
// 
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
//                   Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
// Unit Tests      - http://benalman.com/code/projects/jquery-hashchange/unit/
// 
// About: Known issues
// 
// While this jQuery hashchange event implementation is quite stable and
// robust, there are a few unfortunate browser bugs surrounding expected
// hashchange event-based behaviors, independent of any JavaScript
// window.onhashchange abstraction. See the following examples for more
// information:
// 
// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
// 
// Also note that should a browser natively support the window.onhashchange 
// event, but not report that it does, the fallback polling loop will be used.
// 
// About: Release History
// 
// 1.3   - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
//         "removable" for mobile-only development. Added IE6/7 document.title
//         support. Attempted to make Iframe as hidden as possible by using
//         techniques from http://www.paciellogroup.com/blog/?p=604. Added 
//         support for the "shortcut" format $(window).hashchange( fn ) and
//         $(window).hashchange() like jQuery provides for built-in events.
//         Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
//         lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
//         and <jQuery.fn.hashchange.src> properties plus document-domain.html
//         file to address access denied issues when setting document.domain in
//         IE6/7.
// 1.2   - (2/11/2010) Fixed a bug where coming back to a page using this plugin
//         from a page on another domain would cause an error in Safari 4. Also,
//         IE6/7 Iframe is now inserted after the body (this actually works),
//         which prevents the page from scrolling when the event is first bound.
//         Event can also now be bound before DOM ready, but it won't be usable
//         before then in IE6/7.
// 1.1   - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
//         where browser version is incorrectly reported as 8.0, despite
//         inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
// 1.0   - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
//         window.onhashchange functionality into a separate plugin for users
//         who want just the basic event & back button support, without all the
//         extra awesomeness that BBQ provides. This plugin will be included as
//         part of jQuery BBQ, but also be available separately.

(function($,window,undefined){
  '$:nomunge'; // Used by YUI compressor.
  
  // Reused string.
  var str_hashchange = 'hashchange',
    
    // Method / object references.
    doc = document,
    fake_onhashchange,
    special = $.event.special,
    
    // Does the browser support window.onhashchange? Note that IE8 running in
    // IE7 compatibility mode reports true for 'onhashchange' in window, even
    // though the event isn't supported, so also test document.documentMode.
    doc_mode = doc.documentMode,
    supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
  
  // Get location.hash (or what you'd expect location.hash to be) sans any
  // leading #. Thanks for making this necessary, Firefox!
  function get_fragment( url ) {
    url = url || location.href;
    return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
  };
  
  // Method: jQuery.fn.hashchange
  // 
  // Bind a handler to the window.onhashchange event or trigger all bound
  // window.onhashchange event handlers. This behavior is consistent with
  // jQuery's built-in event handlers.
  // 
  // Usage:
  // 
  // > jQuery(window).hashchange( [ handler ] );
  // 
  // Arguments:
  // 
  //  handler - (Function) Optional handler to be bound to the hashchange
  //    event. This is a "shortcut" for the more verbose form:
  //    jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
  //    all bound window.onhashchange event handlers will be triggered. This
  //    is a shortcut for the more verbose
  //    jQuery(window).trigger( 'hashchange' ). These forms are described in
  //    the <hashchange event> section.
  // 
  // Returns:
  // 
  //  (jQuery) The initial jQuery collection of elements.
  
  // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
  // $(elem).hashchange() for triggering, like jQuery does for built-in events.
  $.fn[ str_hashchange ] = function( fn ) {
    return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
  };
  
  // Property: jQuery.fn.hashchange.delay
  // 
  // The numeric interval (in milliseconds) at which the <hashchange event>
  // polling loop executes. Defaults to 50.
  
  // Property: jQuery.fn.hashchange.domain
  // 
  // If you're setting document.domain in your JavaScript, and you want hash
  // history to work in IE6/7, not only must this property be set, but you must
  // also set document.domain BEFORE jQuery is loaded into the page. This
  // property is only applicable if you are supporting IE6/7 (or IE8 operating
  // in "IE7 compatibility" mode).
  // 
  // In addition, the <jQuery.fn.hashchange.src> property must be set to the
  // path of the included "document-domain.html" file, which can be renamed or
  // modified if necessary (note that the document.domain specified must be the
  // same in both your main JavaScript as well as in this file).
  // 
  // Usage:
  // 
  // jQuery.fn.hashchange.domain = document.domain;
  
  // Property: jQuery.fn.hashchange.src
  // 
  // If, for some reason, you need to specify an Iframe src file (for example,
  // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
  // do so using this property. Note that when using this property, history
  // won't be recorded in IE6/7 until the Iframe src file loads. This property
  // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
  // compatibility" mode).
  // 
  // Usage:
  // 
  // jQuery.fn.hashchange.src = 'path/to/file.html';
  
  $.fn[ str_hashchange ].delay = 50;
  /*
  $.fn[ str_hashchange ].domain = null;
  $.fn[ str_hashchange ].src = null;
  */
  
  // Event: hashchange event
  // 
  // Fired when location.hash changes. In browsers that support it, the native
  // HTML5 window.onhashchange event is used, otherwise a polling loop is
  // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
  // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
  // compatibility" mode), a hidden Iframe is created to allow the back button
  // and hash-based history to work.
  // 
  // Usage as described in <jQuery.fn.hashchange>:
  // 
  // > // Bind an event handler.
  // > jQuery(window).hashchange( function(e) {
  // >   var hash = location.hash;
  // >   ...
  // > });
  // > 
  // > // Manually trigger the event handler.
  // > jQuery(window).hashchange();
  // 
  // A more verbose usage that allows for event namespacing:
  // 
  // > // Bind an event handler.
  // > jQuery(window).bind( 'hashchange', function(e) {
  // >   var hash = location.hash;
  // >   ...
  // > });
  // > 
  // > // Manually trigger the event handler.
  // > jQuery(window).trigger( 'hashchange' );
  // 
  // Additional Notes:
  // 
  // * The polling loop and Iframe are not created until at least one handler
  //   is actually bound to the 'hashchange' event.
  // * If you need the bound handler(s) to execute immediately, in cases where
  //   a location.hash exists on page load, via bookmark or page refresh for
  //   example, use jQuery(window).hashchange() or the more verbose 
  //   jQuery(window).trigger( 'hashchange' ).
  // * The event can be bound before DOM ready, but since it won't be usable
  //   before then in IE6/7 (due to the necessary Iframe), recommended usage is
  //   to bind it inside a DOM ready handler.
  
  // Override existing $.event.special.hashchange methods (allowing this plugin
  // to be defined after jQuery BBQ in BBQ's source code).
  special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
    
    // Called only when the first 'hashchange' event is bound to window.
    setup: function() {
      // If window.onhashchange is supported natively, there's nothing to do..
      if ( supports_onhashchange ) { return false; }
      
      // Otherwise, we need to create our own. And we don't want to call this
      // until the user binds to the event, just in case they never do, since it
      // will create a polling loop and possibly even a hidden Iframe.
      $( fake_onhashchange.start );
    },
    
    // Called only when the last 'hashchange' event is unbound from window.
    teardown: function() {
      // If window.onhashchange is supported natively, there's nothing to do..
      if ( supports_onhashchange ) { return false; }
      
      // Otherwise, we need to stop ours (if possible).
      $( fake_onhashchange.stop );
    }
    
  });
  
  // fake_onhashchange does all the work of triggering the window.onhashchange
  // event for browsers that don't natively support it, including creating a
  // polling loop to watch for hash changes and in IE 6/7 creating a hidden
  // Iframe to enable back and forward.
  fake_onhashchange = (function(){
    var self = {},
      timeout_id,
      
      // Remember the initial hash so it doesn't get triggered immediately.
      last_hash = get_fragment(),
      
      fn_retval = function(val){ return val; },
      history_set = fn_retval,
      history_get = fn_retval;
    
    // Start the polling loop.
    self.start = function() {
      timeout_id || poll();
    };
    
    // Stop the polling loop.
    self.stop = function() {
      timeout_id && clearTimeout( timeout_id );
      timeout_id = undefined;
    };
    
    // This polling loop checks every $.fn.hashchange.delay milliseconds to see
    // if location.hash has changed, and triggers the 'hashchange' event on
    // window when necessary.
    function poll() {
      var hash = get_fragment(),
        history_hash = history_get( last_hash );
      
      if ( hash !== last_hash ) {
        history_set( last_hash = hash, history_hash );
        
        $(window).trigger( str_hashchange );
        
      } else if ( history_hash !== last_hash ) {
        location.href = location.href.replace( /#.*/, '' ) + history_hash;
      }
      
      timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
    };
    
    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    $.browser.msie && !supports_onhashchange && (function(){
      // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
      // when running in "IE7 compatibility" mode.
      
      var iframe,
        iframe_src;
      
      // When the event is bound and polling starts in IE 6/7, create a hidden
      // Iframe for history handling.
      self.start = function(){
        if ( !iframe ) {
          iframe_src = $.fn[ str_hashchange ].src;
          iframe_src = iframe_src && iframe_src + get_fragment();
          
          // Create hidden Iframe. Attempt to make Iframe as hidden as possible
          // by using techniques from http://www.paciellogroup.com/blog/?p=604.
          iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
            
            // When Iframe has completely loaded, initialize the history and
            // start polling.
            .one( 'load', function(){
              iframe_src || history_set( get_fragment() );
              poll();
            })
            
            // Load Iframe src if specified, otherwise nothing.
            .attr( 'src', iframe_src || 'javascript:0' )
            
            // Append Iframe after the end of the body to prevent unnecessary
            // initial page scrolling (yes, this works).
            .insertAfter( 'body' )[0].contentWindow;
          
          // Whenever `document.title` changes, update the Iframe's title to
          // prettify the back/next history menu entries. Since IE sometimes
          // errors with "Unspecified error" the very first time this is set
          // (yes, very useful) wrap this with a try/catch block.
          doc.onpropertychange = function(){
            try {
              if ( event.propertyName === 'title' ) {
                iframe.document.title = doc.title;
              }
            } catch(e) {}
          };
          
        }
      };
      
      // Override the "stop" method since an IE6/7 Iframe was created. Even
      // if there are no longer any bound event handlers, the polling loop
      // is still necessary for back/next to work at all!
      self.stop = fn_retval;
      
      // Get history by looking at the hidden Iframe's location.hash.
      history_get = function() {
        return get_fragment( iframe.location.href );
      };
      
      // Set a new history item by opening and then closing the Iframe
      // document, *then* setting its location.hash. If document.domain has
      // been set, update that as well.
      history_set = function( hash, history_hash ) {
        var iframe_doc = iframe.document,
          domain = $.fn[ str_hashchange ].domain;
        
        if ( hash !== history_hash ) {
          // Update Iframe with any initial `document.title` that might be set.
          iframe_doc.title = doc.title;
          
          // Opening the Iframe's document after it has been closed is what
          // actually adds a history entry.
          iframe_doc.open();
          
          // Set document.domain for the Iframe document as well, if necessary.
          domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
          
          iframe_doc.close();
          
          // Update the Iframe's hash, for great justice.
          iframe.location.hash = hash;
        }
      };
      
    })();
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
    return self;
  })();
  
})(jQuery,this);

/*
 * jQuery SmoothDivScroll 1.1
 *
 * Copyright (c) 2010 Thomas Kahn
 * Licensed under the GPL license.
 *
 * http://www.maaki.com/thomas/SmoothDivScroll/
 *
 * Depends:
 * jquery.ui.widget.js
 *
 */
(function($) {

	$.widget("thomaskahn.smoothDivScroll", {
		// Default options
		options: {
			scrollingHotSpotLeft: "div.scrollingHotSpotLeft",
			scrollingHotSpotRight: "div.scrollingHotSpotRight",
			scrollableArea: "div.scrollableArea",
			scrollWrapper: "div.scrollWrapper",
			hiddenOnStart: false,
			ajaxContentURL: "",
			countOnlyClass: "",
			scrollStep: 15,
			scrollInterval: 10,
			mouseDownSpeedBooster: 3,
			autoScroll: "",
			autoScrollDirection: "right",
			autoScrollStep: 5,
			autoScrollInterval: 10,
			visibleHotSpots: "",
			hotSpotsVisibleTime: 5,
			startAtElementId: ""
		},
		_create: function() {

			// Set variables
			var self = this, o = this.options, el = this.element;

			el.data("scrollWrapper", el.find(o.scrollWrapper));
			el.data("scrollingHotSpotRight", el.find(o.scrollingHotSpotRight));
			el.data("scrollingHotSpotLeft", el.find(o.scrollingHotSpotLeft));
			el.data("scrollableArea", el.find(o.scrollableArea));
			el.data("speedBooster", 1);
			el.data("motherElementOffset", el.offset().left);
			el.data("scrollXPos", 0);
			el.data("hotSpotWidth", el.find(o.scrollingHotSpotLeft).width());
			el.data("scrollableAreaWidth", 0);
			el.data("startingPosition", 0);
			el.data("rightScrollInterval", null);
			el.data("leftScrollInterval", null);
			el.data("autoScrollInterval", null);
			el.data("hideHotSpotBackgroundsInterval", null);
			el.data("previousScrollLeft", 0);
			el.data("pingPongDirection", "right");
			el.data("getNextElementWidth", true);
			el.data("swapAt", null);
			el.data("startAtElementHasNotPassed", true);
			el.data("swappedElement", null);
			el.data("originalElements", el.data("scrollableArea").children(o.countOnlyClass));
			el.data("visible", true);
			el.data("initialAjaxContentLoaded", false);
			el.data("enabled", true);

			// If the user wants to have visible hotspots, here is where it's taken care of
			if (o.autoScroll !== "always") {
				switch (o.visibleHotSpots) {
					case "always":
						self.showHotSpotBackgrounds();
						break;
					case "onstart":
						self.showHotSpotBackgrounds();
						el.data("hideHotSpotBackgroundsInterval", setTimeout(function() {
							self.hideHotSpotBackgrounds("slow");
						}, (o.hotSpotsVisibleTime * 1000)));
						break;
					default:
						break;
				}
			}
			/*****************************************
			SET UP EVENTS FOR SCROLLING RIGHT
			*****************************************/
			// Check the mouse X position and calculate the relative X position inside the right hotspot
			el.data("scrollingHotSpotRight").bind("mousemove", function(e) {
				var x = e.pageX - (this.offsetLeft + el.data("motherElementOffset"));
				el.data("scrollXPos", Math.round((x / el.data("hotSpotWidth")) * o.scrollStep));
				if (el.data("scrollXPos") === Infinity) {
					el.data("scrollXPos", 0);
				}
			});

			// mouseover right hotspot - scrolling
			el.data("scrollingHotSpotRight").bind("mouseover", function() {

				// Clear autoscrolling, if it should only run on start
				if ((o.autoScroll === "onstart" && el.data("autoScrollInterval") !== null)) {
					clearInterval(el.data("autoScrollInterval"));
					el.data("autoScrollInterval", null);
					self._trigger("autoScrollIntervalStopped");
				}

				// Start the scrolling interval
				el.data("rightScrollInterval", setInterval(function() {

					if (el.data("scrollXPos") > 0 && el.data("enabled")) {
						el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + (el.data("scrollXPos") * el.data("speedBooster")));

						self._showHideHotSpots();
					}

				}, o.scrollInterval));

				// Callback
				self._trigger("mouseOverRightHotSpot");

			});

			// mouseout right hotspot
			el.data("scrollingHotSpotRight").bind("mouseout", function() {
				clearInterval(el.data("rightScrollInterval"));
				el.data("scrollXPos", 0);
			});

			// mousedown right hotspot (add scrolling speed booster)
			el.data("scrollingHotSpotRight").bind("mousedown", function() {
				el.data("speedBooster", o.mouseDownSpeedBooster);
			});

			// mouseup anywhere (stop boosting the scrolling speed)
			$("body").bind("mouseup", function() {
				el.data("speedBooster", 1);
			});

			/*****************************************
			SET UP EVENTS FOR SCROLLING LEFT
			*****************************************/
			// Check the mouse X position and calculate the relative X position inside the left hotspot
			el.data("scrollingHotSpotLeft").bind("mousemove", function(e) {
				var x = el.data("scrollingHotSpotLeft").innerWidth() - (e.pageX - el.data("motherElementOffset"));
				el.data("scrollXPos", Math.round((x / el.data("hotSpotWidth")) * o.scrollStep));
				if (el.data("scrollXPos") === Infinity) {
					el.data("scrollXPos", 0);
				}

			});

			// mouseover left hotspot
			el.data("scrollingHotSpotLeft").bind("mouseover", function() {

				// Clear autoscrolling, if it should only run on start

				if ((o.autoScroll === "onstart" && el.data("autoScrollInterval") !== null)) {
					clearInterval(el.data("autoScrollInterval"));
					el.data("autoScrollInterval", null);
					self._trigger("autoScrollIntervalStopped");
				}

				el.data("leftScrollInterval", setInterval(function() {
					if (el.data("scrollXPos") > 0 && el.data("enabled")) {
						el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - (el.data("scrollXPos") * el.data("speedBooster")));

						self._showHideHotSpots();
					}

				}, o.scrollInterval));

				// Callback
				self._trigger("mouseOverLeftHotSpot");
			});

			// mouseout left hotspot
			el.data("scrollingHotSpotLeft").bind("mouseout", function() {
				clearInterval(el.data("leftScrollInterval"));
				el.data("scrollXPos", 0);
			});

			// mousedown left hotspot (add scrolling speed booster)
			el.data("scrollingHotSpotLeft").bind("mousedown", function() {
				el.data("speedBooster", o.mouseDownSpeedBooster);
			});

			/*****************************************
			SET UP EVENT FOR RESIZING THE BROWSER WINDOW
			*****************************************/
			$(window).bind("resize", function() {
				// If the scrollable area is not hidden on start, show/hide the hotspots
				if (!(o.hiddenOnStart)) {
					self._showHideHotSpots();
				}

				self._trigger("windowResized");
			});

			/*****************************************
			FETCHING AJAX CONTENT ON INITIALIZATION
			*****************************************/
			// If there's an ajaxContentURL in the options, 
			// fetch the content
			if (o.ajaxContentURL.length > 0) {
				self.replaceContent(o.ajaxContentURL);
			}
			else {
				self.recalculateScrollableArea();
			}

			// Should it be hidden on start?
			if (o.hiddenOnStart) {
				self.hide();
			}

			/*****************************************
			AUTOSCROLLING
			*****************************************/
			// If the user has set the option autoScroll, the scollable area will
			// start scrolling automatically. If the content is fetched using AJAX
			// the autoscroll is not started here but in recalculateScrollableArea.
			// Otherwise recalculateScrollableArea won't have the time to calculate
			// the width of the scrollable area before the autoscrolling starts.
			if ((o.autoScroll.length > 0) && !(o.hiddenOnStart) && (o.ajaxContentURL.length <= 0)) {
				self.startAutoScroll();
			}

		},
		/**********************************************************
		Hotspot functions
		**********************************************************/
		showHotSpotBackgrounds: function(fadeSpeed) {
			// Alter the CSS (SmoothDivScroll.css) if you want to customize
			// the look'n'feel of the visible hotspots
			var self = this, el = this.element;

			// Fade in the hotspot backgrounds
			if (fadeSpeed !== undefined) {
				// Before the fade-in starts, we need to make sure the opacity
				// is zero
				el.data("scrollingHotSpotLeft").css("opacity", "0.0");
				el.data("scrollingHotSpotRight").css("opacity", "0.0");

				el.data("scrollingHotSpotLeft").addClass("scrollingHotSpotLeftVisible");
				el.data("scrollingHotSpotRight").addClass("scrollingHotSpotRightVisible");

				// Fade in the left hotspot
				el.data("scrollingHotSpotLeft").fadeTo(fadeSpeed, 0.35);

				// Fade in the right hotspot
				el.data("scrollingHotSpotRight").fadeTo(fadeSpeed, 0.35);
			}
			// Don't fade, just show them
			else {
				// The left hotspot
				el.data("scrollingHotSpotLeft").addClass("scrollingHotSpotLeftVisible");
				el.data("scrollingHotSpotLeft").removeAttr("style");

				// The right hotspot
				el.data("scrollingHotSpotRight").addClass("scrollingHotSpotRightVisible");
				el.data("scrollingHotSpotRight").removeAttr("style");
			}
			self._showHideHotSpots();
		},
		hideHotSpotBackgrounds: function(fadeSpeed) {
			var el = this.element;

			// Fade out the hotspot backgrounds
			if (fadeSpeed !== undefined) {
				// Fade out the left hotspot
				el.data("scrollingHotSpotLeft").fadeTo(fadeSpeed, 0.0, function() {
					el.data("scrollingHotSpotLeft").removeClass("scrollingHotSpotLeftVisible");
				});

				// Fade out the right hotspot
				el.data("scrollingHotSpotRight").fadeTo(fadeSpeed, 0.0, function() {
					el.data("scrollingHotSpotRight").removeClass("scrollingHotSpotRightVisible");
				});
			}
			// Don't fade, just hide them
			else {
				el.data("scrollingHotSpotLeft").removeClass("scrollingHotSpotLeftVisible");
				el.data("scrollingHotSpotLeft").removeAttr("style");

				el.data("scrollingHotSpotRight").removeClass("scrollingHotSpotRightVisible");
				el.data("scrollingHotSpotRight").removeAttr("style");
			}

		},
		// Function for showing and hiding hotspots depending on the
		// offset of the scrolling
		_showHideHotSpots: function() {
			var self = this, el = this.element, o = this.options;

			// If autoscrolling is set to always, there should be no hotspots
			if (o.autoScroll !== "always") {
				// If the scrollable area is shorter than the scroll wrapper, both hotspots
				// should be hidden
				if (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth())) {
					el.data("scrollingHotSpotLeft").hide();
					el.data("scrollingHotSpotRight").hide();
				}
				// When you can't scroll further left the left scroll hotspot should be hidden
				// and the right hotspot visible.
				else if (el.data("scrollWrapper").scrollLeft() === 0) {
					el.data("scrollingHotSpotLeft").hide();
					el.data("scrollingHotSpotRight").show();
					// Callback
					self._trigger("scrollLeftLimitReached");
					// Clear interval
					clearInterval(el.data("leftScrollInterval"));
					el.data("leftScrollInterval", null);
				}
				// When you can't scroll further right
				// the right scroll hotspot should be hidden
				// and the left hotspot visible
				else if (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth() + el.data("scrollWrapper").scrollLeft())) {
					el.data("scrollingHotSpotLeft").show();
					el.data("scrollingHotSpotRight").hide();
					// Callback
					self._trigger("scrollRightLimitReached");
					// Clear interval
					clearInterval(el.data("rightScrollInterval"));
					el.data("rightScrollInterval", null);
				}
				// If you are somewhere in the middle of your
				// scrolling, both hotspots should be visible
				else {
					el.data("scrollingHotSpotLeft").show();
					el.data("scrollingHotSpotRight").show();
				}
			}
			else {
				el.data("scrollingHotSpotLeft").hide();
				el.data("scrollingHotSpotRight").hide();
			}
		},
		/**********************************************************
		Moving to a certain element
		**********************************************************/
		moveToElement: function(moveTo, elementNumber) {
			var self = this, el = this.element, o = this.options, tempScrollableAreaWidth = 0, foundStartAtElement = false;

			switch (moveTo) {
				case "first":
					el.data("scrollXPos", 0);
					self._trigger("movedToFirstElement");
					break;
				case "start":
					// Check to see where the start-at element is at the moment.
					// This can vary if endlessloop is used for autoscroll since it
					// swaps elements around.

					el.data("scrollableArea").children(o.countOnlyClass).each(function() {

						if ((o.startAtElementId.length > 0) && (($(this).attr("id")) === o.startAtElementId)) {
							el.data("startingPosition", tempScrollableAreaWidth);
							foundStartAtElement = true;
						}
						tempScrollableAreaWidth = tempScrollableAreaWidth + $(this).outerWidth(true);
					});

					el.data("scrollXPos", el.data("startingPosition"));
					self._trigger("movedToStartElement");
					break;
				case "last":
					el.data("scrollXPos", el.data("scrollableAreaWidth"));
					self._trigger("movedToLastElement");
					break;
				case "number":
					if (!(isNaN(elementNumber))) {
						// Get the total width of all preceding elements					
						el.data("scrollableArea").children(o.countOnlyClass).each(function(index) {
							if (index === (elementNumber - 1)) {
								el.data("scrollXPos", tempScrollableAreaWidth);
							}
							tempScrollableAreaWidth = tempScrollableAreaWidth + $(this).outerWidth(true);
						});
					}
					self._trigger("movedToElementNumber", null, { "elementNumber": elementNumber });
					break;
				default:
					break;
			}

			el.data("scrollWrapper").scrollLeft(el.data("scrollXPos"));
			self._showHideHotSpots();
		},
		/**********************************************************
		Adding or replacing content
		**********************************************************/
		addContent: function(ajaxContentURL, addWhere) {
			var self = this, el = this.element;

			$.get(ajaxContentURL, function(data) {
				// Add the loaded content first or last in the scrollable area
				if (addWhere === "first") {
					el.data("scrollableArea").children(":first").before(data);
				}
				else {
					el.data("scrollableArea").children(":last").after(data);
				}

				// Recalculate the total width of the elements inside the scrollable area
				self.recalculateScrollableArea();

				// Determine which hotspots to show
				self._showHideHotSpots();
			});
		},
		replaceContent: function(ajaxContentURL) {
			var self = this, el = this.element;

			el.data("scrollableArea").load(ajaxContentURL, function() {
				// Recalculate the total width of the elements inside the scrollable area
				self.recalculateScrollableArea();
				self.moveToElement("first");
				self._showHideHotSpots();
				el.data("startingPosition", 0);
			});
		},
		/**********************************************************
		Recalculate the scrollable area
		**********************************************************/
		recalculateScrollableArea: function() {

			var tempScrollableAreaWidth = 0, foundStartAtElement = false, o = this.options, el = this.element, self = this;

			// Add up the total width of all the items inside the scrollable area
			// and check to see if there's a specific element to start at
			el.data("scrollableArea").children(o.countOnlyClass).each(function() {
				// Check to see if the current element in the loop is the one where the scrolling should start
				if ((o.startAtElementId.length > 0) && (($(this).attr("id")) === o.startAtElementId)) {
					el.data("startingPosition", tempScrollableAreaWidth);
					foundStartAtElement = true;
				}
				tempScrollableAreaWidth = tempScrollableAreaWidth + $(this).outerWidth(true);
			});
		
			
			// If the element with the ID specified by startAtElementId
			// is not found, reset it
			if (!(foundStartAtElement)) {
				el.data("startAtElementId", "");
			}

			// Set the width of the scrollable area
			el.data("scrollableAreaWidth", tempScrollableAreaWidth);
			el.data("scrollableArea").width(el.data("scrollableAreaWidth"));

			// Move to the starting position
			el.data("scrollWrapper").scrollLeft(el.data("startingPosition"));
			el.data("scrollXPos", el.data("startingPosition"));

			// If the content of the scrollable area is fetched using AJAX
			// during initialization, it needs to be done here. After it has
			// been loaded a flag variable is set to indicate that the content
			// has been loaded already and shouldn
			if (!(el.data("initialAjaxContentLoaded"))) {
				if ((o.autoScroll.length > 0) && !(o.hiddenOnStart) && (o.ajaxContentURL.length > 0)) {
					self.startAutoScroll();
					el.data("initialAjaxContentLoaded", true);
				}
			}

		},
		/**********************************************************
		Stopping, starting and doing the autoscrolling
		**********************************************************/
		stopAutoScroll: function() {
			var self = this, el = this.element;

			clearInterval(el.data("autoScrollInterval"));
			el.data("autoScrollInterval", null);

			// Check to see which hotspots should be active
			// in the position where the scroller has stopped
			self._showHideHotSpots();

			self._trigger("autoScrollStopped");

		},
		startAutoScroll: function() {
			var self = this, el = this.element, o = this.options;

			self._showHideHotSpots();

			// Stop any running interval
			clearInterval(el.data("autoScrollInterval"));
			el.data("autoScrollInterval", null);

			// Callback
			self._trigger("autoScrollStarted");

			// Start interval
			el.data("autoScrollInterval", setInterval(function() {

				// If the scroller is not visible or
				// if the scrollable area is shorter than the scroll wrapper
				// any running autoscroll interval should stop.
				if (!(el.data("visible")) || (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth()))) {
					// Stop any running interval
					clearInterval(el.data("autoScrollInterval"));
					el.data("autoScrollInterval", null);
				}
				else {
					// Store the old scrollLeft value to see if the scrolling has reached the end
					el.data("previousScrollLeft", el.data("scrollWrapper").scrollLeft());


					switch (o.autoScrollDirection) {
						case "right":
							el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + o.autoScrollStep);
							if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) {
								self._trigger("autoScrollRightLimitReached");
								clearInterval(el.data("autoScrollInterval"));
								el.data("autoScrollInterval", null);
								self._trigger("autoScrollIntervalStopped");
							}
							break;

						case "left":
							el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - o.autoScrollStep);
							if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) {
								self._trigger("autoScrollLeftLimitReached");
								clearInterval(el.data("autoScrollInterval"));
								el.data("autoScrollInterval", null);
								self._trigger("autoScrollIntervalStopped");
							}
							break;

						case "backandforth":
							if (el.data("pingPongDirection") === "right") {
								el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + (o.autoScrollStep));
							}
							else {
								el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - (o.autoScrollStep));
							}

							// If the scrollLeft hasnt't changed it means that the scrolling has reached
							// the end and the direction should be switched
							if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) {
								if (el.data("pingPongDirection") === "right") {
									el.data("pingPongDirection", "left");
									self._trigger("autoScrollRightLimitReached");
								}
								else {
									el.data("pingPongDirection", "right");
									self._trigger("autoScrollLeftLimitReached");
								}
							}
							break;

						case "endlessloopright":
							// Get the width of the first element. When it has scrolled out of view,
							// the element swapping should be executed. A true/false variable is used
							// as a flag variable so the swapAt value doesn't have to be recalculated
							// in each loop.

							if (el.data("getNextElementWidth")) {
								if ((o.startAtElementId.length > 0) && (el.data("startAtElementHasNotPassed"))) {
									el.data("swapAt", $("#" + o.startAtElementId).outerWidth(true));
									el.data("startAtElementHasNotPassed", false);
								}
								else {
									el.data("swapAt", el.data("scrollableArea").children(":first").outerWidth(true));
								}

								el.data("getNextElementWidth", false);
							}

							// Do the autoscrolling
							el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + o.autoScrollStep);

							// Check to see if the swap should be done
							if (el.data("swapAt") <= el.data("scrollWrapper").scrollLeft()) {
								el.data("swappedElement", el.data("scrollableArea").children(":first").detach());
								el.data("scrollableArea").append(el.data("swappedElement"));
								el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - el.data("swappedElement").outerWidth(true));
								el.data("getNextElementWidth", true);
							}
							break;
						case "endlessloopleft":
							// Get the width of the first element. When it has scrolled out of view,
							// the element swapping should be executed. A true/false variable is used
							// as a flag variable so the swapAt value doesn't have to be recalculated
							// in each loop.

							if (el.data("getNextElementWidth")) {
								if ((o.startAtElementId.length > 0) && (el.data("startAtElementHasNotPassed"))) {
									el.data("swapAt", $("#" + o.startAtElementId).outerWidth(true));
									el.data("startAtElementHasNotPassed", false);
								}
								else {
									el.data("swapAt", el.data("scrollableArea").children(":first").outerWidth(true));
								}

								el.data("getNextElementWidth", false);
							}

							// Do the autoscrolling
							el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - o.autoScrollStep);

							// Check to see if the swap should be done
							if (el.data("scrollWrapper").scrollLeft() === 0) {
								el.data("swappedElement", el.data("scrollableArea").children(":last").detach());
								el.data("scrollableArea").prepend(el.data("swappedElement"));
								el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + el.data("swappedElement").outerWidth(true));
								el.data("getNextElementWidth", true);
							}
							break;
						default:
							break;

					}
				}
			}, o.autoScrollInterval));

		},
		restoreOriginalElements: function() {
			var self = this, el = this.element;

			// Restore the original content of the scrollable area
			el.data("scrollableArea").html(el.data("originalElements"));
			self.recalculateScrollableArea();
			self.moveToElement("first");
		},
		show: function() {
			var el = this.element;
			el.data("visible", true);
			el.show();
		},
		hide: function() {
			var el = this.element;
			el.data("visible", false);
			el.hide();
		},
		enable: function() {
			var el = this.element;

			// Set enabled to true
			el.data("enabled", true);
		},
		disable: function() {
			var el = this.element;

			// Clear all running intervals
			clearInterval(el.data("autoScrollInterval"));
			clearInterval(el.data("rightScrollInterval"));
			clearInterval(el.data("leftScrollInterval"));
			clearInterval(el.data("hideHotSpotBackgroundsInterval"));

			// Set enabled to false
			el.data("enabled", false);
		},
		destroy: function() {
			var el = this.element;

			// Clear all running intervals
			clearInterval(el.data("autoScrollInterval"));
			clearInterval(el.data("rightScrollInterval"));
			clearInterval(el.data("leftScrollInterval"));
			clearInterval(el.data("hideHotSpotBackgroundsInterval"));

			// Remove all element specific events
			el.data("scrollingHotSpotRight").unbind("mouseover");
			el.data("scrollingHotSpotRight").unbind("mouseout");
			el.data("scrollingHotSpotRight").unbind("mousedown");

			el.data("scrollingHotSpotLeft").unbind("mouseover");
			el.data("scrollingHotSpotLeft").unbind("mouseout");
			el.data("scrollingHotSpotLeft").unbind("mousedown");

			// Restore the original content of the scrollable area
			el.data("scrollableArea").html(el.data("originalElements"));

			// Remove the width of the scrollable area
			el.data("scrollableArea").removeAttr("style");
			el.data("scrollingHotSpotRight").removeAttr("style");
			el.data("scrollingHotSpotLeft").removeAttr("style");

			el.data("scrollWrapper").scrollLeft(0);
			el.data("scrollingHotSpotLeft").removeClass("scrollingHotSpotLeftVisible");
			el.data("scrollingHotSpotRight").removeClass("scrollingHotSpotRightVisible");
			el.data("scrollingHotSpotRight").hide();
			el.data("scrollingHotSpotLeft").hide();

			// Call the base destroy function
			$.Widget.prototype.destroy.apply(this, arguments);

		}
	});
})(jQuery);
