      */
     override public function styleChanged(styleProp:String):void
     {
+        super.styleChanged(styleProp);
+        
         var allStyles:Boolean = (styleProp == null || styleProp == "styleName");
-        super.styleChanged(styleProp);
+        
         if (allStyles || styleProp == "horizontalScrollPolicy" || 
             styleProp == "verticalScrollPolicy")
         {
             invalidateSkin();
         }
+        
+        if (allStyles || styleProp == "inputMode")
+        {
+            if (getStyle("inputMode") == "touch")
+            {
+                installTouchListeners();
+                
+                touchScrollHelper = new TouchScrollHelper(this);
+                touchScrollHelper.horizontalSlop = MIN_HORIZONTAL_SLOP;
+                touchScrollHelper.verticalSlop = MIN_VERTICAL_SLOP;
+                touchScrollHelper.diagonalSlop = MIN_DIAGONAL_SLOP;
+            }
+            else
+            {
+                uninstallTouchListeners();
+            }
+        }
+    }
+    
+    /**
+     *  @private
+     */
+    private function installTouchListeners():void
+    {
+        addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
+        addEventListener(TouchScrollEvent.TOUCH_SCROLL_STARTING, touchScrollStartingHandler);
+        addEventListener(TouchScrollEvent.TOUCH_SCROLL_START, touchScrollStartHandler);
+        addEventListener(TouchScrollEvent.TOUCH_SCROLL_DRAG, touchScrollDragHandler);
+        addEventListener(TouchScrollEvent.TOUCH_SCROLL_END, touchScrollEndHandler);
+        addEventListener(TouchScrollEvent.TOUCH_SCROLL_THROW, touchScrollThrowHandler);
+    }
+    
+    // ScrollerLayout vars
+    public var horizontalScrollInProgress:Boolean = false;
+    public var verticalScrollInProgress:Boolean = false;
+    
+    // SLOP CONSTANTS
+    private static const MIN_HORIZONTAL_SLOP:int = 10;
+    private static const MIN_VERTICAL_SLOP:int = 10;
+    private static const MIN_DIAGONAL_SLOP:int = 10;
+    
+    /**
+     *  @private
+     */
+    private function uninstallTouchListeners():void
+    {
+        removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
+        removeEventListener(TouchScrollEvent.TOUCH_SCROLL_STARTING, touchScrollStartingHandler);
+        removeEventListener(TouchScrollEvent.TOUCH_SCROLL_START, touchScrollStartHandler);
+        removeEventListener(TouchScrollEvent.TOUCH_SCROLL_END, touchScrollEndHandler);
+        removeEventListener(TouchScrollEvent.TOUCH_SCROLL_DRAG, touchScrollDragHandler);
+        removeEventListener(TouchScrollEvent.TOUCH_SCROLL_THROW, touchScrollThrowHandler);
+    }
+    
+    private function touchScrollStartingHandler(event:TouchScrollEvent):void
+    {
+        if (event.scrollingObject != this)
+        {
+            touchScrollHelper.stopScrollWatch();
+        }
+    }
+    
+    private function touchScrollStartHandler(event:TouchScrollEvent):void
+    {
+        installSwallowingMouseHandlers();
+        hspBeforeTouchScroll = viewport.horizontalScrollPosition;
+        vspBeforeTouchScroll = viewport.verticalScrollPosition;
+        
+        if (viewport.scrollAxis == "horizontal" || viewport.scrollAxis == "diagonal")
+            horizontalScrollInProgress = true;
+        if (viewport.scrollAxis == "vertical" || viewport.scrollAxis == "diagonal")
+            verticalScrollInProgress = true;
+        
+        // need to invaliadte the ScrollerLayout object so it'll update the
+        // scrollbars in overlay mode
+        skin.invalidateDisplayList();
+    }
+    
+    private function installSwallowingMouseHandlers():void
+    {
+        // block click events from occuring on me
+        addEventListener(MouseEvent.CLICK, touchScrolling_captureMouseHandler, true);
+        addEventListener(MouseEvent.MOUSE_DOWN, touchScrolling_captureMouseHandler, true);
+//        addEventListener(MouseEvent.MOUSE_OVER, touchScrolling_captureMouseHandler, true);
+//        addEventListener(MouseEvent.ROLL_OVER, touchScrolling_captureMouseHandler, true);
+    }
+    
+    private function uninstallSwallowingMouseHandlers():void
+    {
+        removeEventListener(MouseEvent.CLICK, touchScrolling_captureMouseHandler, true);
+        removeEventListener(MouseEvent.MOUSE_DOWN, touchScrolling_captureMouseHandler, true);
+//        removeEventListener(MouseEvent.MOUSE_OVER, touchScrolling_captureMouseHandler, true);
+//        removeEventListener(MouseEvent.ROLL_OVER, touchScrolling_captureMouseHandler, true);
+    }
+    
+    private var stoppedPreemptively:Boolean = false;
+    
+    private function touchScrolling_captureMouseHandler(event:MouseEvent):void
+    {
+        switch(event.type)
+        {
+            case MouseEvent.MOUSE_DOWN:
+                if (throwEffect && throwEffect.isPlaying)
+                {
+                    // stop the effect.  we don't want to move it to its final value...we want to stop it in place
+                    // FIXME (rfrishbe): however if it's below 0 or above maxVSP, we should snap it to these values
+                    stoppedPreemptively = true;
+                    throwEffect.stop();
+                    
+                    // get new values in case we start scrolling again
+                    hspBeforeTouchScroll = viewport.horizontalScrollPosition;
+                    vspBeforeTouchScroll = viewport.verticalScrollPosition;
+                }
+                
+                touchScrollHelper.startScrollWatch(event);
+                event.stopImmediatePropagation();
+                break;
+            case MouseEvent.ROLL_OVER:
+            case MouseEvent.MOUSE_OVER:
+            case MouseEvent.CLICK:
+                event.stopImmediatePropagation();
+                break;
+        }
+    }
+    
+    private function mouseDownHandler(event:MouseEvent):void
+    {
+        // FIXME (rfrishbe): if currently scrolling, we should stop scrolling 
+        // and move the VSP/HSP in to range (0, maxVSP).
+               
+        touchScrollHelper.startScrollWatch(event);
+    }
+    
+    private var touchScrollHelper:TouchScrollHelper;
+    private var hspBeforeTouchScroll:Number;
+    private var vspBeforeTouchScroll:Number;
+    
+    private function touchScrollDragHandler(event:TouchScrollEvent):void
+    {
+        var xMove:int = 0;
+        var yMove:int = 0;
+        
+        if (viewport.scrollAxis == "horizontal" || viewport.scrollAxis == "diagonal")
+            xMove = event.dragX;
+        
+        if (viewport.scrollAxis == "vertical" || viewport.scrollAxis == "diagonal")
+            yMove = event.dragY
+
+        // FIXME (rfrishbe): figure out how we want negative signs to work
+        viewport.horizontalScrollPosition = hspBeforeTouchScroll - xMove;
+        viewport.verticalScrollPosition = vspBeforeTouchScroll - yMove;
+    }
+    
+    private function touchScrollEndHandler(event:TouchScrollEvent):void
+    {
+        horizontalScrollInProgress = false;
+        verticalScrollInProgress = false;
+        uninstallSwallowingMouseHandlers();
+        
+        // need to invaliadte the ScrollerLayout object so it'll update the
+        // scrollbars in overlay mode
+        skin.invalidateDisplayList();
+    }
+    
+    private var throwEaser:TouchScrollingEasing;
+    private var EFFECT_TIME:int = 3000;
+    private var throwEffect:Animate;
+    
+    private function setUpThrowEffect(velocity:Point):void
+    {
+        if (!throwEffect)
+        {
+            throwEffect = new Animate();
+            throwEffect.addEventListener(EffectEvent.EFFECT_END, throwEffect_effectEndHandler);
+            
+            throwEaser = new TouchScrollingEasing(0);
+        }
+        var finalHSP:Number = viewport.horizontalScrollPosition;
+        var finalVSP:Number = viewport.verticalScrollPosition;
+        
+        // want velocity to be 0 and to decrease by currentFriction every 
+        // SCROLLING_TIMER_DELAY over EFFECT_TIME total
+        var decelerationRate:Point = velocity.clone();
+        decelerationRate.x = decelerationRate.x/EFFECT_TIME;
+        decelerationRate.y = decelerationRate.y/EFFECT_TIME;
+        
+        // figure out where we're scrolling to
+        if (viewport.scrollAxis == "horizontal" || viewport.scrollAxis == "diagonal")
+        {
+            var hsp:Number = viewport.horizontalScrollPosition;
+            var viewportWidth:Number = isNaN(viewport.width) ? 0 : viewport.width;
+            var cWidth:Number = viewport.contentWidth;
+            var maxWidth:Number = Math.max(0, (cWidth == 0) ? viewport.horizontalScrollPosition : cWidth - viewportWidth);
+            
+            // initialVelocity.y * ellapsedTime - (0.5 * frictionToUse * ellapsedTime * ellapsedTime);
+            finalHSP = viewport.horizontalScrollPosition - (velocity.x * EFFECT_TIME) + (.5 * decelerationRate.x * EFFECT_TIME * EFFECT_TIME);
+//            finalHSP = Math.max(0, Math.min(finalHSP, maxWidth));
+            
+        }
+        
+        if (viewport.scrollAxis == "vertical" || viewport.scrollAxis == "diagonal")
+        {
+            var vsp:Number = viewport.verticalScrollPosition;
+            var viewportHeight:Number = isNaN(viewport.height) ? 0 : viewport.height;
+            var cHeight:Number = viewport.contentHeight;
+            var maxHeight:Number = Math.max(0, (cHeight == 0) ? viewport.verticalScrollPosition : cHeight - viewportHeight);
+            
+            // initialVelocity.y * ellapsedTime - (0.5 * frictionToUse * ellapsedTime * ellapsedTime);
+            finalVSP = viewport.verticalScrollPosition - (velocity.y * EFFECT_TIME) + (.5 * decelerationRate.y * EFFECT_TIME * EFFECT_TIME);
+//            finalVSP = Math.max(0, Math.min(finalVSP, maxHeight));
+        }
+        
+        // set up easer.  Sometimes these values won't be exactly right, but it shouldn't 
+        // matter if maxHeight is wrong as long as we aren't actually moving it around
+        // in that axis.
+        throwEaser.velocity = velocity;
+        throwEaser.maxHeight = maxHeight;
+        throwEaser.maxWidth = maxWidth;
+        throwEaser.maxExtraY = viewportHeight;
+        throwEaser.maxExtraX = viewportWidth;
+        
+        // FIXME (rfrishbe): could move some of this to a setup function to do only once
+        // set up throw effect
+        throwEffect.target = viewport;
+        throwEffect.duration = EFFECT_TIME;
+        
+        // maybe use motion paths with more keyframes for the bounce effect??
+        var horizontalMP:MotionPath = new SimpleMotionPath("horizontalScrollPosition", hsp, finalHSP);
+        var verticalMP:MotionPath = new SimpleMotionPath("verticalScrollPosition", vsp, finalVSP);
+        
+        if (viewport.scrollAxis == "diagonal")
+            throwEffect.motionPaths = Vector.<MotionPath>([horizontalMP, verticalMP]);
+        else if (viewport.scrollAxis == "horizontal")
+            throwEffect.motionPaths = Vector.<MotionPath>([horizontalMP]);
+        else if (viewport.scrollAxis == "vertical")
+            throwEffect.motionPaths = Vector.<MotionPath>([verticalMP]);
+        
+        throwEffect.easer = throwEaser;
+    }
+    
+    private function throwEffect_effectEndHandler(event:EffectEvent):void
+    {
+        // if we stopped the effect ourself (because someone pressed down), then let's not consider
+        // this the end
+        if (stoppedPreemptively)
+            return;
+        
+        dispatchEvent(new TouchScrollEvent(TouchScrollEvent.TOUCH_SCROLL_THROW_ANIMATION_END));
+    }
+    
+    private function touchScrollThrowHandler(event:TouchScrollEvent):void
+    {
+        stoppedPreemptively = false;
+        setUpThrowEffect(event.throwVelocity);
+        throwEffect.play();
     }
 
     /**


package spark.components
{
import flash.events.Event;
import flash.events.FocusEvent;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.system.ApplicationDomain;
import flash.text.TextField;
import flash.ui.Keyboard;

import spark.components.Group;
import spark.components.supportClasses.ScrollerLayout;
import spark.components.supportClasses.SkinnableComponent;
import spark.core.IViewport;
import spark.core.NavigationUnit;
import mx.core.IInvalidating;
import mx.core.IVisualElement;
import mx.core.IVisualElementContainer;
import mx.core.LayoutDirection;
import mx.core.ScrollPolicy;
import mx.events.PropertyChangeEvent;
import mx.managers.IFocusManagerComponent;
import flash.display.InteractiveObject;

include "../styles/metadata/BasicInheritingTextStyles.as"
include "../styles/metadata/AdvancedInheritingTextStyles.as"

}

}

import flash.display.DisplayObject;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TouchEvent;
import flash.geom.Point;
import flash.utils.getTimer;

import mx.events.SandboxMouseEvent;

import spark.components.Scroller;
import spark.events.TouchScrollEvent;

class TouchScrollHelper
{
    private static const HISTORY:int = 5;
    private static const MIN_START_VELOCITY:Number = 0.05;
    
    private static function calculateVelocity(clickHistory:Vector.<Point>, timeHistory:Vector.<int>):Vector.<Point>
    {
        var len:int = clickHistory.length - 1;
        if (len <= 0)
            
            return null;
        
        var velocities:Vector.<Point> = new Vector.<Point>(len);
        
        for (var i:int = 0; i < len; i++)
        {
            var point1:Point = clickHistory[i];
            var point2:Point = clickHistory[i+1];
            var distance:Point = point2.subtract(point1);
            var time:Number = timeHistory[i+1] - timeHistory[i];
            velocities[i] = new Point(distance.x/time, distance.y/time);
        }
        
        return velocities;
    }
    
    private static function averagePoints(points:Vector.<Point>, weighted:Vector.<Number>):Point
    {
        var len:int = points.length;
        
        var currentPoint:Point = new Point(0, 0);
        var totalWeight:Number = 0;
        
        for (var i:int = 0; i < len; i++)
        {
            var point:Point = new Point(points[i].x, points[i].y);
            totalWeight += weighted[i];
            point.x *= weighted[i];
            point.y *= weighted[i];
            currentPoint.x += point.x;
            currentPoint.y += point.y;
        }
        
        currentPoint.x = currentPoint.x/totalWeight;
        currentPoint.y = currentPoint.y/totalWeight;
        
        return currentPoint;
    }
    
    public function TouchScrollHelper(scroller:Scroller)
    {
        super();
        
        clickHistory = new Vector.<Point>();
        timeHistory = new Vector.<int>();
        
        this.scroller = scroller;
    }
    
    public var horizontalSlop:Number;
    public var verticalSlop:Number;
    public var diagonalSlop:Number;
    public var scroller:Scroller;
    
    // each of these per mouseEvent (or per touchPoint ID)
    private var mouseDownedPoint:Point;
    private var scrollStartPoint:Point;
    private var startTime:Number;
    private var mouseDownedDisplayObject:DisplayObject;
    private var clickHistory:Vector.<Point>;
    private var timeHistory:Vector.<int>;
    private var isScrolling:Boolean;
    
    public function startScrollWatch(event:Event):void
    {
        startTime = flash.utils.getTimer();
        
        if (event is MouseEvent && event.type == MouseEvent.MOUSE_DOWN)
        {
            var mouseEvent:MouseEvent = event as MouseEvent;
            
            if (!isScrolling)
            {
                this.mouseDownedDisplayObject = mouseEvent.target as DisplayObject;
                
                mouseDownedPoint = new Point(mouseEvent.stageX, mouseEvent.stageY);
            }
            
            installMouseListeners();
            
            // if we were already scrolling, continue scrolling
            if (isScrolling)
            {
                // FIXME (rfrishbe): below is same as in mouseMove...should it be?
//                var scrollDragStartEvent:TouchScrollEvent = new TouchScrollEvent(TouchScrollEvent.TOUCH_SCROLL_START);
//                scrollDragStartEvent.scrollingObject = scroller;
//                scroller.dispatchEvent(scrollDragStartEvent);
                scrollStartPoint = new Point(mouseEvent.stageX, mouseEvent.stageY);
            }
            
            // only need to do this stuff once per target
            // store last 5 values
            clickHistory.length = 0;
            timeHistory.length = 0;
            
            addMouseEventHistory(mouseEvent);
        }
        else if (event is TouchEvent && event.type == TouchEvent.TOUCH_BEGIN)
        {
            // TouchEvent case
        }            
    }
    
    public function stopScrollWatch():void
    {
        uninstallMouseListeners();
    }
    
    private function addMouseEventHistory(event:MouseEvent):Point
    {
        var p:Point = new Point(event.stageX, event.stageY);
        var differencePoint:Point = p.subtract(mouseDownedPoint);
        
        if (clickHistory.length >= HISTORY)
        {
            clickHistory.shift();
            timeHistory.shift();
        }
        
        clickHistory.push(differencePoint);
        timeHistory.push(flash.utils.getTimer() - startTime);
        
        return differencePoint;
    }

    // event listener helpers
    private function installMouseListeners():void
    {
        var sbRoot:DisplayObject = scroller.systemManager.getSandboxRoot();
        
        sbRoot.addEventListener(MouseEvent.MOUSE_MOVE, sbRoot_mouseMoveHandler, true);
        sbRoot.addEventListener(MouseEvent.MOUSE_UP, sbRoot_mouseUpHandler, true);
        sbRoot.addEventListener(SandboxMouseEvent.MOUSE_UP_SOMEWHERE, sbRoot_mouseUpHandler);
        
        scroller.systemManager.deployMouseShields(true);
    }
    
    private function uninstallMouseListeners():void
    {
        var sbRoot:DisplayObject = scroller.systemManager.getSandboxRoot();
        
        // mouse events added in installMouseListeners()
        sbRoot.removeEventListener(MouseEvent.MOUSE_MOVE, sbRoot_mouseMoveHandler, true);
        sbRoot.removeEventListener(MouseEvent.MOUSE_UP, sbRoot_mouseUpHandler, true);
        sbRoot.removeEventListener(SandboxMouseEvent.MOUSE_UP_SOMEWHERE, sbRoot_mouseUpHandler);
        
        scroller.systemManager.deployMouseShields(false);
    }
    
    // event listeners
    /**
     *  @private
     * 
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */
    protected function sbRoot_mouseMoveHandler(event:MouseEvent):void
    {
        var mouseDownedDifference:Point = addMouseEventHistory(event);
        
        if (!isScrolling)
        {
            var shouldBeScrolling:Boolean = false;
            
            switch (scroller.viewport.scrollAxis)
            {
                case "vertical":
                    shouldBeScrolling = Math.abs(mouseDownedDifference.y) >= verticalSlop;
                    break;
                case "horizontal":
                    shouldBeScrolling = Math.abs(mouseDownedDifference.x) >= horizontalSlop;
                    break;
                case "diagonal":
                    shouldBeScrolling = Math.abs(mouseDownedDifference.length) >= diagonalSlop;
                    break;
            }
            
            // Check to see if we should be scrolling
            if (shouldBeScrolling)
            {
                // cancellable and bubbling event
                var scrollDragStartingEvent:TouchScrollEvent = new TouchScrollEvent(TouchScrollEvent.TOUCH_SCROLL_STARTING, true, true);
                scrollDragStartingEvent.scrollingObject = scroller;
                var eventAccepted:Boolean = mouseDownedDisplayObject.dispatchEvent(scrollDragStartingEvent);
                
                if (!eventAccepted)
                {                    
                    // TODO (rfrishbe): do we need to call updateAfterEvent() here and below?
                    event.updateAfterEvent();
                    
                    // if our mouse target has been rejected, let's give up and remove all the listeners
                    uninstallMouseListeners();
                    
                    return;
                }
                
                var scrollDragStartEvent:TouchScrollEvent = new TouchScrollEvent(TouchScrollEvent.TOUCH_SCROLL_START);
                scrollDragStartEvent.scrollingObject = scroller;
                scroller.dispatchEvent(scrollDragStartEvent);
                
                // FIXME (rfrishbe): the difference should not be from the original point but from the slop.
                // otherwise we "jump" on the first move.
                // we should reset startPoint here to be this point minus slop (in the direction that caused the scroll)
                scrollStartPoint = new Point(event.stageX, event.stageY);
                isScrolling = true;
                
                // velocity calculations come from mouseDownedPoint.  The drag ones com from scrollStartPoint.
            }
            
            
        }
        
        // if we are scrolling
        if (isScrolling)
        {
            var p:Point = new Point(event.stageX, event.stageY);
            var scrollDifferencePoint:Point = p.subtract(scrollStartPoint);
            
            var scrollDragEvent:TouchScrollEvent = new TouchScrollEvent(TouchScrollEvent.TOUCH_SCROLL_DRAG, false, false);
            scrollDragEvent.scrollingObject = scroller;
            scrollDragEvent.dragX = scrollDifferencePoint.x;
            scrollDragEvent.dragY = scrollDifferencePoint.y;
            
            scroller.dispatchEvent(scrollDragEvent);
            event.updateAfterEvent();
        }
    }
    
    /**
     *  @private
     *  Called when the user releases the TitleWindow.
     * 
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 1.5
     *  @productversion Flex 4
     */
    protected function sbRoot_mouseUpHandler(event:Event):void
    {
        uninstallMouseListeners();
        
        // FIXME (rfrishbe): can we scroll by velocity even tho no drag took place?
        if (!isScrolling)
            return;
        
        if (event is MouseEvent)
            addMouseEventHistory(event as MouseEvent);
        
        // decide about throw
        
        // pad click and timeHistory if needed
        var currentTime:Number = getTimer();
        
        // calculate average time b/w events and see if the last two (mouseMove and this mouseUp) 
        // were far apart.  If they were, then don't do anything if the velocity of them is small.
        var averageTime:Number = 0;
        var len:int = timeHistory.length;
        
        // FIXME (rfrishbe): this isn't true sine we could get a mouseUpSomehwere event
        // gauranteed to have 2 mouse events b/c atleast a mousedown and a mouse up
        
        for (var i:int = 0; i < len - 2; i++)
        {
            averageTime += timeHistory[i+1] - timeHistory[i];
        }
        averageTime /= len-2;
        
        var lastTime:Number = timeHistory[len-1] - timeHistory[len-2];
        var lastVelocity:Point = clickHistory[len-1].subtract(clickHistory[len-2]);
        lastVelocity.x /= lastTime;
        lastVelocity.y /= lastTime;
        
        // FIXME (rfrishbe): should be minXVelocity, minYVelocity, minDiagonalVelocity
        // FIXME (rfrishbe): this should be parameterized better
        if ( (lastTime >= 3*averageTime) &&
            (lastVelocity.length <= MIN_START_VELOCITY))
        {
            isScrolling = false;
            
            // don't do anything
            var scrollEndEvent:TouchScrollEvent = new TouchScrollEvent(TouchScrollEvent.TOUCH_SCROLL_END);
            scrollEndEvent.scrollingObject = scroller;
            scroller.dispatchEvent(scrollEndEvent);
            return;
        }
        
        
        var velocities:Vector.<Point> = calculateVelocity(clickHistory, timeHistory);
        
        var velocityWeights:Vector.<Number> = Vector.<Number>([1,1.33,1.66,2]);
        var throwVelocity:Point = averagePoints(velocities, velocityWeights);
        
        //            trace("velocity: ", initialVelocity.y);
        if (throwVelocity.length > MIN_START_VELOCITY)
        {
            var scrollEndAndThrowEvent:TouchScrollEvent = new TouchScrollEvent(TouchScrollEvent.TOUCH_SCROLL_THROW, false, false);
            scrollEndAndThrowEvent.scrollingObject = scroller;
            scrollEndAndThrowEvent.throwVelocity = throwVelocity;
            
            scroller.addEventListener(TouchScrollEvent.TOUCH_SCROLL_THROW_ANIMATION_END, scroller_touchScrollThrowAnimationEnd);
            scroller.dispatchEvent(scrollEndAndThrowEvent);
        }
        
        // if we own this user gesture, don't let others see this event
//        if (isScrolling)
//            event.stopImmediatePropagation();
    }
    
    private function scroller_touchScrollThrowAnimationEnd(event:TouchScrollEvent):void
    {
        scroller.removeEventListener(TouchScrollEvent.TOUCH_SCROLL_THROW_ANIMATION_END, scroller_touchScrollThrowAnimationEnd);
        
        isScrolling = false;
        
        var scrollEndEvent:TouchScrollEvent = new TouchScrollEvent(TouchScrollEvent.TOUCH_SCROLL_END);
        scrollEndEvent.scrollingObject = scroller;
        scroller.dispatchEvent(scrollEndEvent);
    }
    
    
}
