/**
 * Constructor of a specific scrollbar.
 * Requires jQuery Mousewheel Plugin.
 * 
 * @param       object      see check below for details
 *
 * Throws an exception if wrong options are specified.
 */
function GoJoyScrollbar(options)
{
    // Check the given options.
    var areCorrectOptions =
        
        // The argument must be an object.
        typeof(options) == "object"
        
        // Scrollable content must be specified.
        && "content" in options
        && options.content instanceof jQuery
        && options.content.size() > 0
        
        // Scrollable content's pane must be specified.
        && "pane" in options
        && options.pane instanceof jQuery
        && options.pane.size() > 0
        
        // Scrollbar block must be specified.
        && "scrollbar" in options
        && options.pane instanceof jQuery
        && options.pane.size() > 0
        
        // Srcollbar must contains a scroller and overlay.
        && options.scrollbar.is(":has(.scroller)")
        && options.scrollbar.is(":has(.scroller-overlay)")
        
        // Orientation of the scrollbar must be specified.
        && "orientation" in options
        && (options.orientation == "horizontal" || options.orientation == "vertical")
    ;
    
    // Throw an exception if wrong options are specified.
    if ( ! areCorrectOptions)
    {
        throw "Wrong options are specified.";
    }
    
    
    // Specify configuration of the scrollbar.
    var configuration =
    {
        "orientation" : options.orientation
    };
    
    
    // Collect elements that are used in scrolling process.
    var elements =
    {
        "content"   : options.content,
        "overlay"   : options.scrollbar.find(".scroller-overlay"),
        "pane"      : options.pane,
        "scrollbar" : options.scrollbar,
        "scroller"  : options.scrollbar.find(".scroller")
    };
    
    // Move the content and the scroller to the beginning.
    switch (configuration.orientation)
    {
        case "horizontal":
            elements.content.css("margin-left", 0);
            elements.scroller.css("margin-left", 0);
            break;
            
        case "vertical":
            elements.content.css("margin-top", 0);
            elements.scroller.css("top", 0);
            break;
    }
    
    
    
    // Functions to control the scrollbar.
    var Scrollbar = new Object();
    
    // -------------------------------------------------------------------------
    
    /**
     * Animated Scrolling by Content Offset
     */
    (function ()
    {
        // Indicator of animation process.
        var isAnimationInProcess = false;
        
        
        /**
         * Does an animated scrolling by content offset.
         *
         * @param       number      a content offset
         * @param       mixed       jQuery animation duration
         */
        Scrollbar.animatedScrollingByContentOffset = function (offset, duration)
        {
            if (Scrollbar.getContentRatio() >= 1)
            {
                return;
            }
        
            // If an animation is already in process, add the call to queue.
            if (isAnimationInProcess)
            {
                return;
            }
            
            // Specify that animation is in process.
            isAnimationInProcess = true;
            
            
            // Get the scroller offset.
            var scrollerOffset = Scrollbar.contentOffsetToScrollerOffset(offset);
            
            // Normalize the content offset.
            contentOffset = Scrollbar.normalizeContentOffset(offset);
            
            // Don't continue the animation if the offset is null.
            if (contentOffset == 0)
            {
                // Specify that the animation is finished.
                isAnimationInProcess = false;
                
                return;
            }
            
            
            // Animate the scrolling.
            
            var contentProperties;
            var scrollerProperties;
            switch (configuration.orientation)
            {
                case "horizontal":
                    contentProperties = { "margin-left" : "-=" + contentOffset + "px"};
                    scrollerProperties = { "margin-left" : "+=" + scrollerOffset + "px"};
                    break;
                    
                case "vertical":
                    contentProperties = { "margin-top" : "-=" + contentOffset + "px"};
                    scrollerProperties = { "top" : "+=" + scrollerOffset + "px" };
                    break;
            }
            
            elements.content.animate
            (
                contentProperties,
                { "duration" : duration, "complete" : function () { isAnimationInProcess = false; } } 
            );
            
            elements.scroller.animate
            (
                scrollerProperties, { "duration" : duration }
            );
        
        };  // END Scrollbar.animatedScrollingByContentOffset = function (offset, duration)
    
    })();   // END Animated Scrolling by Content Offset
    
    // -------------------------------------------------------------------------
    
    /**
     * Calculates excess of a content offset.
     *
     * @param       number      a content offset
     * @return      number      excess of a given content offset
     */
    Scrollbar.contentOffsetExcess = function (contentOffset)
    {
        return contentOffset - Scrollbar.normalizeContentOffset(contentOffset);
    
    };  // END Scrollbar.contentOffsetExcess = function (contentOffset)
    
    // -------------------------------------------------------------------------
    
    /**
     * Converts a content offset to a scroller offset considering the ratios.
     * Normalizes calculated scroller offset.
     *
     * @param       number      a content offset
     * @return      number      calculated and normalized scroller offset
     */
    Scrollbar.contentOffsetToScrollerOffset = function (contentOffset)
    {
        // Calculate the current scroller position.
        var contentPosition = Scrollbar.getContentOffset() + contentOffset;
        
        var scrollerOffset;
    
        // Reset (normalize) the scroller offset if it exceeds the boundaries.
        if (contentPosition < 0)
        {
            // The offset exceeds the lower boundary.
        
            // Calculate the offsets to move the scrollbar in the beginning.
            contentOffset = (-1) * Scrollbar.getContentOffset();
            scrollerOffset = (-1) * Scrollbar.getScrollerOffset();
        }
        else if (contentPosition > Scrollbar.getMaximumContentOffset())
        {
            // The offset exceeds the higher boundary.
        
            // Calculate the offsets to move the scrollbar at the end.
        
            contentOffset =
                Scrollbar.getMaximumContentOffset() - Scrollbar.getContentOffset()
            ;
        
            scrollerOffset =
                Scrollbar.getMaximumScrollerOffset() - Scrollbar.getScrollerOffset()
            ;
        }
        else
        {
            // The offset doesn't exceed boundaries (the most common case).
            
            var scrollerPosition;
            
            // Check whether the ratios are equal.
            if (Scrollbar.getContentRatio() == Scrollbar.getScrollerRatio())
            {
                // The ratios are equal (the most common case).
                
                // Calculate the exact scroller position.
                scrollerPosition =
                    (Scrollbar.getScrollbarSize() * contentPosition) / Scrollbar.getContentSize()
                ;
            }
            else
            {
                // The ratios are different (the very special case when the
                // content size is too large).
                
                scrollerPosition =
                    (Scrollbar.getMaximumScrollerOffset() * contentPosition) / Scrollbar.getMaximumContentOffset()
                ;
            }
            
            // Calculate the scroller offset.
            scrollerOffset = scrollerPosition - Scrollbar.getScrollerOffset();
        }
        
        // Return the calculated and normalized content offset.
        return scrollerOffset;
    
    };  // END Scrollbar.contentOffsetToScrollerOffset = function (contentOffset)
    
    // -------------------------------------------------------------------------
    
    /**
     * Gets the current content offset.
     *
     * @return      number
     */
    Scrollbar.getContentOffset = function ()
    {
        var offset;
        
        // Calculate the content offset.
        switch (configuration.orientation)
        {
            case "horizontal":
                offset = parseFloat
                (
                    elements.content.css("margin-left")
                );
                break;
                
            case "vertical":
                offset = parseFloat
                (
                    elements.content.css("margin-top")
                );
                break;
        }
        
        return Math.abs(offset);
    
    };  // END Scrollbar.getContentOffset = function ()
    
    // -------------------------------------------------------------------------
    
    /**
     * Ratio Controls
     */
    (function ()
    {
        // The ratio of pane size to content size.
        var contentRatio;
        
        // The ratio of scroller size to scrollbar size.
        var scrollerRatio;
        
        
        /**
         * Gets the calculated content ratio.
         *
         * @return      number
         */
        Scrollbar.getContentRatio = function ()
        {
            return contentRatio;
            
        };  // END Scrollbar.getContentRatio = function ()
        
        
        /**
         * Recalculates the ratio, updates size of the scroller.
         */
        Scrollbar.recalculateRatio = function ()
        {
            // Show the scrollbar if it's needed.
            elements.scrollbar.show();
            
        
            // Remember the current content offset.
            var contentOffset = Scrollbar.getContentOffset();
        
            
            // Move content and scroller in the beginning.
            switch (configuration.orientation)
            {
                case "horizontal":
                    elements.content.css("margin-left", 0);
                    elements.scroller.css("margin-left", 0);
                    break;
                    
                case "vertical":
                    elements.content.css("margin-top", 0);
                    elements.scroller.css("top", 0);
                    break;
            }
            
        
            // Calculate the ratio.
            contentRatio = Scrollbar.getPaneSize() / Scrollbar.getContentSize();
            
            // Check whether the content overflows the pane's borders.
            if (contentRatio >= 1)
            {
                // Hide the scrollbar if it's not longer needed.
                elements.scrollbar.hide();
            }
            else
            {
                // Calculate size of the scrolller.
                var scrollerSize = Scrollbar.getScrollbarSize() * contentRatio;
                
                // Specify the scroller ratio.
                if (scrollerSize >= Scrollbar.getMinimumScrollerSize())
                {
                    // The most common case.
                    scrollerRatio = contentRatio;
                }
                else
                {
                    // The very specific case.
                    scrollerRatio =
                        Scrollbar.getMinimumScrollerSize() / Scrollbar.getScrollbarSize()
                    ;
                    
                    // Set the scroller size to its minimum value.
                    scrollerSize = Scrollbar.getMinimumScrollerSize();
                }
                
                // Set the scroller size.
                Scrollbar.setScrollerSize(scrollerSize);
            
            
                // Show the scrollbar if it's needed.
                elements.scrollbar.show();
                
                
                // Move the content by previous offset.
                Scrollbar.scrollByContentOffset(contentOffset);
            }
        
        };  // END Scrollbar.recalculateRatio = function ()
        
        
        /**
         * Gets the calculated scroller ratio.
         *
         * @return      number
         */
        Scrollbar.getScrollerRatio = function ()
        {
            return scrollerRatio;
            
        };  // END Scrollbar.getContentRatio = function ()
    
    })();   // END Ratio Controls
    
    // -------------------------------------------------------------------------
    
    /**
     * Gets size of the content.
     *
     * @return      number
     */
    Scrollbar.getContentSize = function ()
    {
        switch (configuration.orientation)
        {
            case "horizontal": return elements.content.width();
            case "vertical": return elements.content.height();
        }
    
    };  // END Scrollbar.getContentSize = function ()
    
    // -------------------------------------------------------------------------
    
    /**
     * Calculates the maximum offset of the scrollable content.
     *
     * @return      number
     */
    Scrollbar.getMaximumContentOffset = function ()
    {
        return Scrollbar.getContentSize() - Scrollbar.getPaneSize();
        
    };  // END Scrollbar.getMaximumContentOffset = function ()
    
    // -------------------------------------------------------------------------
    
    /**
     * Calculates the maximum offset of scroller in the scrollbar.
     *
     * @return      number
     */
    Scrollbar.getMaximumScrollerOffset = function ()
    {
        return Scrollbar.getScrollbarSize() - Scrollbar.getScrollerSize();
        
    };  // END Scrollbar.getMaximumScrollerOffset = function ()
    
    // -------------------------------------------------------------------------
    
    /**
     * Gets the minimum scroller size.
     *
     * @return      number
     */
    Scrollbar.getMinimumScrollerSize = function ()
    {
        switch (configuration.orientation)
        {
            case "horizontal": return 52;
            case "vertical": return 52;
        }
    
    };  // END Scrollbar.getMinimumScrollerSize = function ()
    
    // -------------------------------------------------------------------------
    
    /**
     * Gets the current size of the pane.
     *
     * @return      number
     */
    Scrollbar.getPaneSize = function ()
    {
        switch (configuration.orientation)
        {
            case "horizontal": return elements.pane.width();
            case "vertical": return elements.pane.height();
        }
    
    };  // END Scrollbar.getPaneSize = function ()
    
    // -------------------------------------------------------------------------
    
    /**
     * Gets size of the scrollbar.
     *
     * @return      number
     */
    Scrollbar.getScrollbarSize = function ()
    {
        switch (configuration.orientation)
        {
            case "horizontal": return elements.scrollbar.width();
            case "vertical":  return elements.scrollbar.height();
        }
    
    };  // END Scrollbar.getScrollbarSize = function ()
    
    // -------------------------------------------------------------------------
    
    /**
     * Gets the current scroller offset.
     *
     * @return      number
     */
    Scrollbar.getScrollerOffset = function ()
    {
        switch (configuration.orientation)
        {
            case "horizontal":
                return parseFloat
                (
                    elements.scroller.css("margin-left")
                );
                
            case "vertical":
                return parseFloat
                (
                    elements.scroller.css("top")
                );
        }
    
    };  // END Scrollbar.getScrollerOffset = function ()
    
    // -------------------------------------------------------------------------
    
    /**
     * Gets the current size of the scroller.
     *
     * @return      number
     */
    Scrollbar.getScrollerSize = function ()
    {
        switch (configuration.orientation)
        {
            case "horizontal": return elements.scroller.width();
            case "vertical":  return elements.scroller.height();
        }
        
    };  // END Scrollbar.getScrollerSize = function ()
    
    // -------------------------------------------------------------------------
    
    /**
     * Normalizes a content offset (if it's needed).
     *
     * @param       number      a content offset
     * @return      number      normalized content offset
     */
    Scrollbar.normalizeContentOffset = function (contentOffset)
    {
        // Calculate the current scroller position.
        var contentPosition = Scrollbar.getContentOffset() + contentOffset;
    
        // Normalize the scroller offset if it exceeds the boundaries.
        if (contentPosition < 0)
        {
            // The offset exceeds the lower boundary.
        
            // Calculate the offset to move the content in the beginning.
            contentOffset = (-1) * Scrollbar.getContentOffset();
        }
        else if (contentPosition > Scrollbar.getMaximumContentOffset())
        {
            // The offset exceeds the higher boundary.
        
            // Calculate the offset to move the content at the end.
        
            contentOffset =
                Scrollbar.getMaximumContentOffset() - Scrollbar.getContentOffset()
            ;
        }
        
        // Return the normalized content offset.
        return contentOffset;
        
    };  // END Scrollbar.normalizeContentOffset = function (contentOffset)
    
    // -------------------------------------------------------------------------
    
    /**
     * Normalizes a scroller offset (if it's needed).
     *
     * @param       number      a scroller offset
     * @return      number      normalized scroller offset
     */
    Scrollbar.normalizeScrollerOffset = function (scrollerOffset)
    {
        // Calculate the current scroller position.
        var scrollerPosition = Scrollbar.getScrollerOffset() + scrollerOffset;    
    
        // Reset (normalize) the scroller offset if it exceeds the boundaries.
        if (scrollerPosition < 0)
        {
            // The offset exceeds the lower boundary.
        
            // Calculate the offset to move the scroller in the beginning.
            scrollerOffset = (-1) * Scrollbar.getScrollerOffset();
        }
        else if (scrollerPosition > Scrollbar.getMaximumScrollerOffset())
        {
            // The offset exceeds the higher boundary.
        
            // Calculate the offset to move the scroller at the end.
        
            scrollerOffset =
                Scrollbar.getMaximumScrollerOffset() - Scrollbar.getScrollerOffset()
            ;
        }
        
        // Return the normalized scroller offset.
        return scrollerOffset;
    
    };  // END Scrollbar.normalizeScrollerOffset = function (scrollerOffset)
    
    // -------------------------------------------------------------------------

    /**
     * Offsets the content by a given value.
     *
     * @param       number      a content offset
     */
    Scrollbar.offsetContent = function (contentOffset)
    {
        // Calculate the content position.
        var contentPosition = Scrollbar.getContentOffset() + contentOffset;
        
        // Set the new content position.
        switch (configuration.orientation)
        {
            case "horizontal":
                elements.content.css("margin-left", -contentPosition + "px");
                break;
                
            case "vertical":
                elements.content.css("margin-top", -contentPosition + "px");
                break;
        }
    
    };  // END Scrollbar.offsetContent = function (contentOffset)
    
    // -------------------------------------------------------------------------
    
    /**
     * Offsets the scroller by a given value.
     *
     * @param       number      a scroller offset
     */
    Scrollbar.offsetScroller = function (scrollerOffset)
    {
        // Calculate the content position.
        var scrollerPosition = Scrollbar.getScrollerOffset() + scrollerOffset;
        
        // Set the new content position.
        switch (configuration.orientation)
        {
            case "horizontal":
                elements.scroller.css("margin-left", scrollerPosition + "px");
                break;
                
            case "vertical":
                elements.scroller.css("top", scrollerPosition + "px");
                break;
        }
    
    };  // END Scrollbar.offsetScroller = function (scrollerOffset)
    
    // -------------------------------------------------------------------------
    
    /**
     * Returns an appropriate page coordinate from a jQuery event object.
     *
     * @param       object      jQuery event
     * @return      number      an appropriate page coordinate
     */
    Scrollbar.getPageCoordinate = function (event)
    {
        switch (configuration.orientation)
        {
            case "horizontal": return event.pageX;
            case "vertical": return event.pageY;
        }
    
    };  // END Scrollbar.getPageCoordinate = function (event)
    
    // -------------------------------------------------------------------------
    
    /**
     * Scrolls the content (and the scroller).
     *
     * @param       number
     */
    Scrollbar.scrollByContentOffset = function (contentOffset)
    {
        // Terminate the function if the content doesn't overflows the pane.
        if (Scrollbar.getContentRatio() >= 1)
        {
            return;
        }
        
        
        // An offset must be a valid integer number.
        contentOffset = parseInt(contentOffset);
        
        // Don't continue if the given offset is not a number or equals to zero.
        if (isNaN(contentOffset) || contentOffset == 0)
        {
            return;
        }
        
        
        // Calculate the scroller offset.
        var scrollerOffset = Scrollbar.contentOffsetToScrollerOffset(contentOffset);
        
        // Normalize the content offset.
        contentOffset = Scrollbar.normalizeContentOffset(contentOffset);
        
        
        // Move the scrollbar.
        Scrollbar.offsetContent(contentOffset);
        Scrollbar.offsetScroller(scrollerOffset);
    
    };  // END Scrollbar.scrollByContentOffset = function (contentOffset)
    
    // -------------------------------------------------------------------------
    
    /**
     * Scrolls the scroller (and the content).
     *
     * @param       number
     */
    Scrollbar.scrollByScrollerOffset = function (scrollerOffset)
    {
        // Terminate the function if the content doesn't overflows the pane.
        if (Scrollbar.getContentRatio() >= 1)
        {
            return;
        }
        
        
        // An offset must be a valid integer number.
        scrollerOffset = parseInt(scrollerOffset);
        
        // Don't continue if the given offset is not a number or equals to zero.
        if (isNaN(scrollerOffset) || scrollerOffset == 0)
        {
            return;
        }
        
        
        // Calculate the content offset.
        var contentOffset = Scrollbar.scrollerOffsetToContentOffset(scrollerOffset);
        
        // Normalize the scroller offset.
        scrollerOffset = Scrollbar.normalizeScrollerOffset(scrollerOffset);
        
        
        // Move the scrollbar.
        Scrollbar.offsetScroller(scrollerOffset);
        Scrollbar.offsetContent(contentOffset);
    
    };  // END Scrollbar.scrollByScrollerOffset = function (scrollerOffset)
    
    // -------------------------------------------------------------------------
    
    /**
     * Calculates excess of a scroller offset.
     *
     * @param       number      a scroller offset
     * @return      number      excess of the scroller offset
     */
    Scrollbar.scrollerOffsetExcess = function (scrollerOffset)
    {
        return scrollerOffset - Scrollbar.normalizeScrollerOffset(scrollerOffset);
    
    };  // END Scrollbar.scrollerOffsetExcess = function (scrollerOffset)
    
    // -------------------------------------------------------------------------
    
    /**
     * Converts a scroller offset to a content offset considering the ratios.
     * Normalizes calculated content offset.
     *
     * @param       number      a scroller offset
     * @return      number      calculated and normalized content offset
     */
    Scrollbar.scrollerOffsetToContentOffset = function (scrollerOffset)
    {
        // Calculate the current scroller position.
        var scrollerPosition = Scrollbar.getScrollerOffset() + scrollerOffset;
        
        var contentOffset;
    
        // Reset (normalize) the scroller offset if it exceeds the boundaries.
        if (scrollerPosition < 0)
        {
            // The offset exceeds the lower boundary.
        
            // Calculate the offsets to move the scrollbar in the beginning.
            scrollerOffset = (-1) * Scrollbar.getScrollerOffset();
            contentOffset = (-1) * Scrollbar.getContentOffset();
        }
        else if (scrollerPosition > Scrollbar.getMaximumScrollerOffset())
        {
            // The offset exceeds the higher boundary.
        
            // Calculate the offsets to move the scrollbar at the end.
        
            scrollerOffset =
                Scrollbar.getMaximumScrollerOffset() - Scrollbar.getScrollerOffset()
            ;
            
            contentOffset =
                Scrollbar.getMaximumContentOffset() - Scrollbar.getContentOffset()
            ;
        }
        else
        {
            // The offset doesn't exceed boundaries (the most common case).
            
            var contentPosition;
            
            // Check whether the ratios are equal.
            if (Scrollbar.getContentRatio() == Scrollbar.getScrollerRatio())
            {
                // The ratios are equal (the most common case).
                
                // Calculate the exact content position.
                contentPosition =
                    (Scrollbar.getContentSize() * scrollerPosition) / Scrollbar.getScrollbarSize()
                ;
                
                
            }
            else
            {
                // The ratios are different (the very special case when the
                // content size is too large).
                
                contentPosition =
                    (Scrollbar.getMaximumContentOffset() * scrollerPosition) / Scrollbar.getMaximumScrollerOffset()
                ;
            }
            
            // Calculate the content offset.
            contentOffset = contentPosition - Scrollbar.getContentOffset();
        }
        
        // Return the calculated and normalized content offset.
        return contentOffset;
    
    };  // END Scrollbar.scrollerOffsetToContentOffset = function (scrollerOffset)
    
    // -------------------------------------------------------------------------
    
    /**
     * Sets size of the scroller.
     *
     * @param       number      a new scroller size
     */
    Scrollbar.setScrollerSize = function (size)
    {
        switch (configuration.orientation)
        {
            case "horizontal":
                elements.scroller.width(size);
                break;
                
                
            case "vertical":
                
                elements.scroller.height(size);
                
                elements.scroller
                    .find(".wrapper")
                    .height(size)
                ;
                
                elements.scroller
                    .find(".center")
                    .height(size)
                ;
                
                break;
        }
        
    };  // END Scrollbar.getScrollerSize = function ()
    
    // ------------------------------------------------ -------------------------
    
    // Calculate the ratios.
    Scrollbar.recalculateRatio();
    
    
    /**
     * Hand Scrolling by Scroller
     */
    (function ()
    {
        // Scrolling indicator.
        var isScrolling = false;
        
        // The current page coordinate.
        var pageCoordinate;
        
        
        // Starts hand scrolling.
        elements.overlay.mousedown(function (event)
        {
            // Specify that hand scrolling is started.
            isScrolling = true;
            
            // Save the current page coordinate.
            pageCoordinate = Scrollbar.getPageCoordinate(event);
            
        });
        
        
        // Do a hand scrolling.
        jQuery(document).mousemove(function (event)
        {
            // Terminate the function if a hand scrolling is not started.
            if ( ! isScrolling)
            {
                return;
            }
            
            
            // Calculate the scroller offset.
            var offset = Scrollbar.getPageCoordinate(event) - pageCoordinate;
            
            // Get the offset excess.
            var excess = Scrollbar.scrollerOffsetExcess(offset);
            
            // Save the page coordinate.
            pageCoordinate += offset - excess;
            
            
            // Do scrolling.
            Scrollbar.scrollByScrollerOffset(offset);
        });
        
        
        // Stop hand scrolling.
        jQuery(document).mouseup(function ()
        {
            // Stop scrolling.
            if (isScrolling)
            {
                isScrolling = false;
            }
        });
    
    })();   // END Hand Scrolling by Scroller
    
    
    /**
     * Scrolling on Mouse Wheel
     */
    (function ()
    {
        // Duration of a scrolling animation.
        var duration = 400;
        
        // Scrolling offset (equals to a list item width).
        var offset;
        switch (configuration.orientation)
        {
            case "horizontal": offset = 310; break;
            case "vertical": offset = 100; break;
        }
        
        
        function mouseWheelHandler(event, delta)
        {
            // Prevent the default action.
            event.preventDefault();
        
            if (delta > 0)
            {
                Scrollbar.animatedScrollingByContentOffset(-offset, duration);
            }
            else if (delta < 0)
            {
                Scrollbar.animatedScrollingByContentOffset(offset, duration);
            }
        }
        
        
        // Set scrolling on mouse wheel events.
        elements.overlay.mousewheel(mouseWheelHandler);
        elements.content.mousewheel(mouseWheelHandler);
        
    })();   // END Scrolling on Mouse Wheel
    
    
    this.animatedScrollingByContentOffset = Scrollbar.animatedScrollingByContentOffset;
    this.recalculateRatio = Scrollbar.recalculateRatio;
    this.getContentRatio = Scrollbar.getContentRatio;

}   // END function GoJoyScrollbar(options)
