/*! Copyright (c) 2011 Piotr Rochala (http://rocha.la), Lanre Adebambo
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * Version: 1.3.7
 *
 */
(function($) {

  $.fn.extend({
    slimScroll: function(options) {

      var defaults = {

        // axis to apply scrollbars x(X) / y(Y) / both
        axis: 'y',

        // width in pixels of the visible scroll area
        width : 'auto',

        // height in pixels of the visible scroll area
        height : '250px',

        // width in pixels of the scrollbar and rail
        size : '7px',

        // scrollbar color, accepts any hex/color value
        color: '#000',

        // scrollbar position - top/bottom
        positionX : 'bottom',

        // scrollbar position - left/right
        positionY : 'right',

        // distance in pixels between the side edge and the scrollbar
        distance : '1px',

        // default scroll position on load - left/right / $('selector')
        startX : 'left',

        // default scroll position on load - top / bottom / $('selector')
        startY : 'top',

        // sets scrollbar opacity
        opacity : 0.4,

        // enables always-on mode for the scrollbar
        alwaysVisible : false,

        // check if we should hide the scrollbar when user is hovering over
        disableFadeOut : false,

        // sets visibility of the rail
        railVisible : false,

        // sets rail color
        railColor : '#333',

        // sets rail opacity
        railOpacity : 0.2,

        // whether  we should use jQuery UI Draggable to enable bar dragging
        railDraggable : true,

        // defautlt CSS class of the slimscroll rail in X axis
        railClassX : 'slimScrollRailX',

        // defautlt CSS class of the slimscroll bar in X Axis
        barClassX : 'slimScrollBarX',

        // defautlt CSS class of the slimscroll rail in Y axis
        railClassY : 'slimScrollRailY',

        // defautlt CSS class of the slimscroll bar in Y axis
        barClassY : 'slimScrollBarY',

        // defautlt CSS class of the slimscroll wrapper
        wrapperClass : 'slimScrollDiv',

        animate: false,

        // check if mousewheel should scroll the window if we reach top/bottom
        allowPageScroll : false,

        // scroll amount applied to each mouse wheel step
        wheelStep : 20,

        // scroll amount applied when user is using gestures
        touchScrollStep : 200,

        // sets border radius
        borderRadius: '7px',

        // sets border radius of the rail
        railBorderRadius : '7px',

		// handler, when slimScroll runned
		'ggSlimscrollHandler': false,
      };

      var o = $.extend(defaults, options);

      // normalize to lower case for ease of handling
      o.axis = o.axis.toLowerCase();

      // do it for every element that matches selector
      this.each(function(){
      var hasHorizontalScrollbar;
      var hasVerticalScrollbar;
      var t, pageX, pageY;
      var isOverPanel, isOverBarX, isOverBarY, isDragg, queueHideX, queueHideY, touchDifX, touchDifY,
        barHeight, barWidth, percentScrollX, lastScrollX, percentScrollY, lastScrollY,
        divS = '<div></div>',
        minBarHeight = 30,
        minBarWidth = 30,
        releaseScroll = false;

        // used in event handlers and for better minification
        var me = $(this);
        var $doc = $(document);

        // ensure we are not binding it again
        if (me.parent().hasClass(o.wrapperClass))
        {
            $.extend(o, (me.data('slimScrollConfig') || {})); //retrieve previous config
            // start from last bar position
            var offset_horizontal = me.scrollLeft();
            var offset_vertical = me.scrollTop();

            // find bar and rail
            barX = me.siblings('.' + o.barClassX);
            railX = me.siblings('.' + o.railClassX);
            barY = me.siblings('.' + o.barClassY);
            railY = me.siblings('.' + o.railClassY);

            //check that scroll bars are enabled
            hasHorizontalScrollbar = (o.axis == 'both' || o.axis == 'x');
            hasVerticalScrollbar = (o.axis == 'both' || o.axis == 'y');

            getBarXWidth();
            getBarYHeight();

            // check if we should scroll existing instance
            if ($.isPlainObject(options))
            {

              // Pass width: auto to an existing slimscroll object to force a resize after contents have changed
              if ( 'width' in options && hasHorizontalScrollbar) {
                if (options.width == 'auto') {
                  me.parent().css('width', 'auto');
                  me.css('width', 'auto');
                  o.width = me.parent().parent().width();
                }
                else {
                  o.width = options.width;
                  me.css({'white-space': 'nowrap'});
                }
              }

              // Pass height: auto to an existing slimscroll object to force a resize after contents have changed
              if ( 'height' in options && hasVerticalScrollbar) {
                if(options.height == 'auto'){
                  me.parent().css('height', 'auto');
                  me.css('height', 'auto');
                  o.height = me.parent().parent().height();
                } else {
                  o.height = options.height;
                }
              }

              // rewrap content
              me.parent().css({
                  position: 'relative',
                  overflow: 'hidden',
                  width: o.width,
                  height: o.height
                });

              // update style for the div
              me.css({
                overflow: 'hidden',
                width: o.width,
                height: o.height
              });

              if ('scrollToX' in options)
              {
                // jump to a static point
                offset_horizontal = parseInt(o.scrollToX);
              }
              else if ('scrollByX' in options)
              {
                // jump by value pixels
                offset_horizontal += parseInt(o.scrollByX);
              }
              if ('scrollToY' in options)
              {
                // jump to a static point
                offset_vertical = parseInt(o.scrollToY);
              }
              else if ('scrollByY' in options)
              {
                // jump by value pixels
                offset_vertical += parseInt(o.scrollByY);
              }

              if ('destroy' in options)
              {
                // remove slimscroll elements
                barX.remove();
                railX.remove();
                barY.remove();
                railY.remove();
                me.unwrap();
                return;
              }
            }
            // scroll content by the given offset
            scrollContent(offset_horizontal, offset_vertical, false, true);

            return;
        }
        else if ($.isPlainObject(options))
        {
            if ('destroy' in options)
            {
            	return;
            }
        }

        //check that scroll bars are enabled
        hasHorizontalScrollbar = (o.axis == 'both' || o.axis == 'x');
        hasVerticalScrollbar = (o.axis == 'both' || o.axis == 'y');

        // optionally set height/width to the parent's height/width
        o.height = (o.height == 'auto') ? me.parent().height() : o.height;
        o.width = (o.width == 'auto') ? me.parent().width() : o.width;

        //store options in DOM
        me.data('slimScrollConfig', o);

        // wrap content
        var wrapper = $(divS)
          .addClass(o.wrapperClass)
          .css({
            position: 'relative',
            overflow: 'hidden',
            width: o.width,
            height: o.height
          });

        // update style for the div
        me.css({
          overflow: 'hidden',
          width: o.width,
          height: o.height
        });

        // wrap it
        me.wrap(wrapper);


        if(hasHorizontalScrollbar){
          // if width is specified remove wrapping from text
          if(o.width != 'auto' && hasHorizontalScrollbar){
            me.css({'white-space': 'nowrap'});
          }

          // create scrollbar rail
          var railX = $(divS)
            .addClass(o.railClassX)
            .css({
              width: '100%',
              height: o.size,
              position: 'absolute',
              left: 0,
              display: (o.alwaysVisible && o.railVisible) ? 'block' : 'none',
              'border-radius': o.railBorderRadius,
              background: o.railColor,
              opacity: o.railOpacity,
              zIndex: 90
            });

          // create scrollbar
          var barX = $(divS)
            .addClass(o.barClassX)
            .css({
              background: o.color,
              height: o.size,
              position: 'absolute',
              left: 0,
              opacity: o.opacity,
              display: o.alwaysVisible ? 'block' : 'none',
              'border-radius' : o.borderRadius,
              BorderRadius: o.borderRadius,
              MozBorderRadius: o.borderRadius,
              WebkitBorderRadius: o.borderRadius,
              zIndex: 99
            });

          // set position
          var xPosCss = (o.positionX == 'top') ? { top: o.distance } : { bottom: o.distance };
          railX.css(xPosCss);
          barX.css(xPosCss);

          // append to parent div
          me.parent().append(barX);
          me.parent().append(railX);

          // make it draggable and no longer dependent on the jqueryUI
          if(o.railDraggable){
            barX.on("mousedown", function(e) {
              isDragg = true;
              t = parseFloat(barX.css('left'));
              pageX = e.pageX;

              $doc.on("mousemove.slimscrollX", function(e){
                currLeft = t + e.pageX - pageX;
                barX.css('left', currLeft);
                scrollContent(0, 0, barX.position().left);// scroll content
              });

              $doc.on("mouseup.slimscrollX", function(e) {
                isDragg = false;
                hideBarX();
                $doc.unbind('.slimscrollX');
              });
              return false;
            }).on("selectstart.slimscrollX", function(e){
              e.stopPropagation();
              e.preventDefault();
              return false;
            });

            railX.on("mousedown", function(e){
              var deltaX = (e.offsetX - (barWidth/2))* me[0].scrollWidth / me.outerWidth();
              scrollContent(deltaX, 0, false, true);// scroll content
              t = parseFloat(barX.css('left'));
              pageX = e.pageX;

              $doc.on("mousemove.slimscrollX", function(e){
                currLeft = t + e.pageX - pageX;
                barX.css('left', currLeft);
                scrollContent(0, 0, barX.position().left);// scroll content
              });

              $doc.on("mouseup.slimscrollX", function(e) {
                isDragg = false;
                hideBarX();
                $doc.unbind('.slimscrollX');
              });
              return false;
            });
          }

          // on rail over
          railX.hover(function(){
            showBarX();
          }, function(){
            hideBarX();
          });

          // on bar over
          barX.hover(function(){
            isOverBarX = true;
          }, function(){
            isOverBarX = false;
          });

          // set up initial width and height
          getBarXWidth();

          // check start position
          if (o.startX === 'right')
          {
            // scroll content to rigth
            barX.css({ left: me.outerWidth() - barX.outerWidth() });
            scrollContent(0, 0, true);
          }
          else if (o.startX !== 'left')
          {
            // assume jQuery selector
            scrollContent($(o.startX).position().left, null, null, true);

            // make sure bar stays hidden
            if (!o.alwaysVisible) { barX.hide(); }
          }

        }


        if(hasVerticalScrollbar){
          // create scrollbar rail
          var railY = $(divS)
            .addClass(o.railClassY)
            .css({
              width: o.size,
              height: '100%',
              position: 'absolute',
              top: 0,
              display: (o.alwaysVisible && o.railVisible) ? 'block' : 'none',
              'border-radius': o.railBorderRadius,
              background: o.railColor,
              opacity: o.railOpacity,
              zIndex: 90
            });

          // create scrollbar
          var barY = $(divS)
            .addClass(o.barClassY)
            .css({
              background: o.color,
              width: o.size,
              position: 'absolute',
              top: 0,
              opacity: o.opacity,
              display: o.alwaysVisible ? 'block' : 'none',
              'border-radius' : o.borderRadius,
              BorderRadius: o.borderRadius,
              MozBorderRadius: o.borderRadius,
              WebkitBorderRadius: o.borderRadius,
              zIndex: 99
            });

          var yPosCss = (o.positionY == 'right') ? { right: o.distance } : { left: o.distance };
          railY.css(yPosCss);
          barY.css(yPosCss);

          me.parent().append(barY);
          me.parent().append(railY);

          if(o.railDraggable){
            barY.on("mousedown", function(e) {
              isDragg = true;
              t = parseFloat(barY.css('top'));
              pageY = e.pageY;

              $doc.on("mousemove.slimscrollY", function(e){
                currTop = t + e.pageY - pageY;
                barY.css('top', currTop);
                scrollContent(0, 0, barY.position().top);// scroll content
              });

              $doc.on("mouseup.slimscrollY", function(e) {
                isDragg = false;
                hideBarY();
                $doc.unbind('.slimscrollY');
              });
              return false;
            }).on("selectstart.slimscrollY", function(e){
              e.stopPropagation();
              e.preventDefault();
              return false;
            });

            railY.on("mousedown", function(e){
              var deltaY = (e.offsetY - (barHeight/2))* me[0].scrollHeight / me.outerHeight();
              scrollContent(0, deltaY, false, true);// scroll content
              t = parseFloat(barY.css('top'));
              pageY = e.pageY;

              $doc.on("mousemove.slimscrollY", function(e){
                currTop = t + e.pageY - pageY;
                barY.css('top', currTop);
                scrollContent(0, 0, barY.position().top);// scroll content
              });

              $doc.on("mouseup.slimscrollY", function(e) {
                isDragg = false;
                hideBarY();
                $doc.unbind('.slimscrollY');
              });
              return false;
            });
          }

          // on rail over
          railY.hover(function(){
            showBarY();
          }, function(){
            hideBarY();
          });

          // on bar over
          barY.hover(function(){
            isOverBarY = true;
          }, function(){
            isOverBarY = false;
          });

          getBarYHeight();

          if (o.startY === 'bottom')
          {
            // scroll content to bottom
            barY.css({ top: me.outerHeight() - barY.outerHeight() });
            scrollContent(0, 0, true);
          }
          else if (o.startY !== 'top')
          {
            // assume jQuery selector
            scrollContent(null, $(o.startY).position().top, null, true);

            // make sure bar stays hidden
            if (!o.alwaysVisible) { barY.hide(); }
          }

        }

        // show on parent mouseover
        me.hover(function(){
          isOverPanel = true;
          showBarX();
          showBarY();
          hideBarX();
          hideBarY();
        }, function(){
          isOverPanel = false;
          hideBarX();
          hideBarY();
        });

        // // support for mobile
        // me.on('touchstart', function(e,b){
        //   if (e.originalEvent.touches.length)
        //   {
        //     // record where touch started
        //     touchDifX = e.originalEvent.touches[0].pageX;
        //     touchDifY = e.originalEvent.touches[0].pageY;
        //   }
        // });
		//
        // me.on('touchmove', function(e){
        //   // prevent scrolling the page if necessary
        //   if(!releaseScroll)
        //   {
  		//       e.originalEvent.preventDefault();
		 //      }
        //   if (e.originalEvent.touches.length)
        //   {
        //     // see how far user swiped
        //     var diffX = (touchDifX - e.originalEvent.touches[0].pageX) / o.touchScrollStep;
        //     var diffY = (touchDifY - e.originalEvent.touches[0].pageY) / o.touchScrollStep;
        //     // scroll content
        //     scrollContent(diffX, diffY, true);
        //     touchDifX = e.originalEvent.touches[0].pageX;
        //     touchDifY = e.originalEvent.touches[0].pageY;
        //   }
        // });
        //enable gesture recognize for this plugin
        var _triggerInit = function() {
          if(typeof(Hammer_gg) == 'undefined') {
            setTimeout(_triggerInit, 100);
            return;
          }

          if(o.isMobile) {
            var hammer = new Hammer_gg(me.context),
                scrollWidth = 50;

            hammer.get('pan').set({
                threshold : scrollWidth
            });

            hammer.on('panleft',function(e) {
                scrollContent(0, scrollWidth, false, false, true);
                panDistance = e.distance;
            });

            hammer.on('panend',function(e) {
                var offset = scrollWidth * (e.velocityX * -1) * 30;
                scrollContent(0, offset, false, false, true);
            });

            hammer.on('panright',function(e) {
                scrollContent(0, -scrollWidth, false, false, true);
                panDistance = e.distance;
            });
          }

        };
        _triggerInit();

        // attach scroll events
        attachWheel(this);

        function _getDeltaFromEvent(e) {
          var deltaX     = 0;
          var deltaY     = 0;

          // Old school scrollwheel delta
          //if ( 'detail'      in e ) { deltaY = e.detail;      }
          //if ( 'wheelDelta'  in e ) { deltaY = -1 * e.wheelDelta / 6;       }
          //if ( 'wheelDeltaY' in e ) { deltaY = -1 * e.wheelDeltaY / 6;      }
          //if ( 'wheelDeltaX' in e ) { deltaX = e.wheelDeltaX / 6; }

		  // stackOverFlow school ))
          deltaX = ((e.deltaX || -e.wheelDelta || e.detail) >> 10) || 1;
          deltaY = ((e.deltaY || -e.wheelDelta || e.detail) >> 10) || 1;

          // Firefox < 17 horizontal scrolling related to DOMMouseScroll event
          if ( 'axis' in e && e.axis === e.HORIZONTAL_AXIS ) {
            deltaX = deltaY * -1;
            deltaY = 0;
          }

          if (deltaX !== deltaX && deltaY !== deltaY/* NaN checks */) {
            // IE in some mouse drivers
            deltaX = 0;
            // deltaY = e.wheelDelta;
          }

          // New school wheel delta (wheel event)
          //if ( 'deltaY' in e ) {
          //  deltaY = e.deltaY;
          //}
          //if ( 'deltaX' in e ) {
          //  deltaX = e.deltaX;
          //}

          return [deltaX, deltaY];
        }

        function _onWheel(e)
        {
          // use mouse wheel only when mouse is over
          if (!isOverPanel) { return; }

          e = e || window.event;

          var delta = _getDeltaFromEvent(e);
          var deltaX = delta[0];
          var deltaY = delta[1];

          // if (e.wheelDelta) { delta = -e.wheelDelta/120; }
          // if (e.detail) { delta = e.detail / 3; }

          var target = e.target || e.srcTarget || e.srcElement;
          if ($(target).closest('.' + o.wrapperClass).is(me.parent())) {
            // scroll content
            scrollContent(deltaX, deltaY, true);
          }

          // stop window scroll
          if (e.preventDefault && !releaseScroll) {
            e.preventDefault();
            e.stopPropagation();
          }
          if (!releaseScroll) { e.returnValue = false; }
        }

        function scrollContent(x, y, isWheel, isJump, isPan)
        {
          releaseScroll = false;
          var needToRunWindowScroll = false,
			  prevBarXOffset = 0;

          if(hasHorizontalScrollbar){
            var deltaX = x;
            var maxLeft = me.outerWidth() - barX.outerWidth(),
                totalWidth = me[0].scrollWidth,
                scrollOffset = me.scrollLeft(),
                barXOffset = parseFloat(barX.css('left'));

            if (isWheel)
            {
              if (!hasVerticalScrollbar) {
                x = y;
              }
              // move bar with mouse wheel
              deltaX = parseInt(barX.css('left')) + (x * parseInt(o.wheelStep));

              // move bar, make sure it doesn't go out
              deltaX = Math.min(Math.max(deltaX, 0), maxLeft);

              // if scrolling right, make sure a fractional change to the
              // scroll position isn't rounded away when the scrollbar's CSS is set
              // this flooring of delta would happened automatically when
              // bar.css is set below, but we floor here for clarity
              deltaX = (x > 0) ? Math.ceil(deltaX) : Math.floor(deltaX);

              // scroll the scrollbar
              barX.css({ left: deltaX + 'px' });
			  // recalc distance for images
			  prevBarXOffset = barXOffset;
			  barXOffset = parseFloat(barX.css('left'));
			  needToRunWindowScroll = (prevBarXOffset == barXOffset);
            }

            // calculate actual scroll amount
            percentScrollX = barXOffset / maxLeft;
            deltaX = percentScrollX * (totalWidth - me.outerWidth());


            if (isPan) {
              deltaX = totalWidth - (totalWidth - scrollOffset - y);

              var panOffsetPercent = deltaX / (totalWidth - me.outerWidth());
              var scrollBarOffset = maxLeft * panOffsetPercent;

              scrollBarOffset = Math.min(Math.max(scrollBarOffset, 0), maxLeft);
              scrollBarOffset = (x > 0) ? Math.ceil(scrollBarOffset) : Math.floor(scrollBarOffset);

              barX.stop(true, true).animate({ left: scrollBarOffset + 'px' }, 300, 'linear');
            }

            if (isJump)
            {
              if (!hasVerticalScrollbar) {
                x = y;
              }
              deltaX = x;
              var offsetLeft = deltaX / me[0].scrollWidth * me.outerWidth();
              offsetLeft = Math.min(Math.max(offsetLeft, 0), maxLeft);
              barX.css({ left: offsetLeft + 'px' });
            }

            // scroll content and fire scrolling event
            if (o.animate){
              me.scrollTop(deltaX); // scroll content smoothly using jquery animation
              me.stop(true, true).animate({ scrollLeft: deltaX }, 500, 'linear');
             } else {
              // scroll content
              me.scrollLeft(deltaX);
            }
            me.trigger('slimscrollingX', ~~deltaX);

            // ensure bar is visible
            showBarX(needToRunWindowScroll);

            // trigger hide when scroll is stopped
            hideBarX();
          }


          if(hasVerticalScrollbar){
            var deltaY = y;
            var maxTop = me.outerHeight() - barY.outerHeight();

            if (isWheel)
            {
              // move bar with mouse wheel
              deltaY = parseInt(barY.css('top')) + (y * parseInt(o.wheelStep) /100);

              // move bar, make sure it doesn't go out
              deltaY = Math.min(Math.max(deltaY, 0), maxTop);

              // if scrolling down, make sure a fractional change to the
              // scroll position isn't rounded away when the scrollbar's CSS is set
              // this flooring of delta would happened automatically when
              // bar.css is set below, but we floor here for clarity
              deltaY = (y > 0) ? Math.ceil(deltaY) : Math.floor(deltaY);

              // scroll the scrollbar
              barY.css({ top: deltaY + 'px' });
            }

            // calculate actual scroll amount
            percentScrollY = parseInt(barY.css('top')) / (me.outerHeight() - barY.outerHeight());
            deltaY = percentScrollY * (me[0].scrollHeight - me.outerHeight());

            if (isJump)
            {
              deltaY = y;
              var offsetTop = deltaY / me[0].scrollHeight * me.outerHeight();
              offsetTop = Math.min(Math.max(offsetTop, 0), maxTop);
              barY.css({ top: offsetTop + 'px' });
            }

            // scroll content and fire scrolling event
            me.scrollTop(deltaY);
            me.trigger('slimscrollingY', ~~deltaY);

            // ensure bar is visible
            showBarY();

            // trigger hide when scroll is stopped
            hideBarY();
          }
          if(o.ggSlimscrollHandler) {
            o.ggSlimscrollHandler();
          }
        }

        function attachWheel(target)
        {
          if (window.addEventListener)
          {
            if (typeof window.onwheel !== "undefined") {
              target.addEventListener('wheel', _onWheel, false );
            } else if (typeof window.onmousewheel !== "undefined") {
              target.addEventListener('mousewheel', _onWheel, false );
            }
            target.addEventListener('DOMMouseScroll', _onWheel, false );
          }
          else
          {
            document.attachEvent("onmousewheel", _onWheel);
          }
        }

        function getBarXWidth()
        {
          if(!barX){return;}
          // calculate scrollbar height and make sure it is not too small
          barWidth = Math.max((me.outerWidth() / me[0].scrollWidth) * me.outerWidth(), minBarWidth);
          barX.css({ width: barWidth + 'px' });

          // hide scrollbar if content is not long enough
          // var display = barWidth == me.outerWidth() ? 'none' : 'block';
          var display = (hasHorizontalScrollbar && (me[0].scrollWidth>me[0].clientWidth)) ? 'block' : 'none';
          barX.css({ display: display });
        }

        function getBarYHeight()
        {
          if(!barY){return;}
          // calculate scrollbar height and make sure it is not too small
          barHeight = Math.max((me.outerHeight() / me[0].scrollHeight) * me.outerHeight(), minBarHeight);
          barY.css({ height: barHeight + 'px' });

          // hide scrollbar if content is not long enough
          // var display = barHeight == me.outerHeight() ? 'none' : 'block';
          var display = (hasVerticalScrollbar && (me[0].scrollHeight>me[0].clientHeight)) ? 'block' : 'none';
          barY.css({ display: display });
        }


        function showBarX(needToRunWindowScroll)
        {
          if(!barX){return;}
          // recalculate bar height
          getBarXWidth();
          clearTimeout(queueHideX);

          // when bar reached top or bottom
          if (percentScrollX == ~~percentScrollX && needToRunWindowScroll)
          {
            //release wheel
            releaseScroll = o.allowPageScroll;

            // publish approporiate event
            if (lastScrollX != percentScrollX)
            {
              var msg = (~~percentScrollX === 0) ? 'left' : 'right';
              me.trigger('slimscrollX', msg);
            }
          }
          else
          {
            releaseScroll = false;
          }
          lastScrollX = percentScrollX;

          // show only when required
          if(barWidth >= me.outerWidth()) {
            //allow window scroll
            releaseScroll = true;
            return;
          }
          barX.fadeIn('fast');
          if (o.railVisible) { railX.stop(true,true).fadeIn('fast'); }
        }

        function hideBarX()
        {
          if(!barX){return;}
          // only hide when options allow it
          if (!o.alwaysVisible)
          {
            queueHideX = setTimeout(function(){
              if (!(o.disableFadeOut && isOverPanel) && !isOverBarX && !isDragg)
              {
                barX.fadeOut('slow');
                railX.fadeOut('slow');
              }
            }, 1000);
          }
        }

        function showBarY()
        {
          if(!barY){return;}
          // recalculate bar height
          getBarYHeight();
          clearTimeout(queueHideY);

          // when bar reached top or bottom
          if (percentScrollY == ~~percentScrollY)
          {
            //release wheel
            releaseScroll = o.allowPageScroll;

            // publish approporiate event
            if (lastScrollY != percentScrollY)
            {
                var msg = (~~percentScrollY === 0) ? 'top' : 'bottom';
                me.trigger('slimscrollY', msg);
            }
          }
          else
          {
            releaseScroll = false;
          }
          lastScrollY = percentScrollY;

          // show only when required
          if(barHeight >= me.outerHeight()) {
            //allow window scroll
            releaseScroll = true;
            return;
          }
          barY.stop(true,true).fadeIn('fast');
          if (o.railVisible) { railY.stop(true,true).fadeIn('fast'); }
        }

        function hideBarY()
        {
          if(!barY){return;}
          // only hide when options allow it
          if (!o.alwaysVisible)
          {
            queueHideY = setTimeout(function(){
              if (!(o.disableFadeOut && isOverPanel) && !isOverBarY && !isDragg)
              {
                barY.fadeOut('slow');
                railY.fadeOut('slow');
              }
            }, 1000);
          }
        }

      });

      // maintain chainability
      return this;
    }
  });

  $.fn.extend({
    slimscroll: $.fn.slimScroll
  });

})(jQuery);
