     
     /**
      *  @private
+     *  Stop the effect if it's currently playing and prepare for a possible scroll
+     */
+    private function stopThrowEffectOnMouseDown():void
+    {
+        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
+            stoppedPreemptively = true;
+            throwEffect.stop();
+                    
+            // Snap the scroll position to the content in case the empty space beyond the edge was visible
+            // due to bounce/pull.
+            var maxHsp:Number = viewport.contentWidth > viewport.width ? viewport.contentWidth-viewport.width : 0; 
+            viewport.horizontalScrollPosition = Math.min(Math.max(0,viewport.horizontalScrollPosition),maxHsp);
+            var maxVsp:Number = viewport.contentHeight > viewport.height ? viewport.contentHeight-viewport.height : 0; 
+            viewport.verticalScrollPosition = Math.min(Math.max(0,viewport.verticalScrollPosition),maxVsp);
+            
+            // get new values in case we start scrolling again
+            hspBeforeTouchScroll = viewport.horizontalScrollPosition;
+            vspBeforeTouchScroll = viewport.verticalScrollPosition;
+        }
+    }
+    
+    /**
+     *  @private
      *  Event listeners added while a scroll/throw animation is in effect
      */
     private function touchScrolling_captureMouseHandler(event:MouseEvent):void

        }
        averageDt /= len-1;
        
        // use the amount they've used as well as the velocity to denote how far to throw the list.
        // to do this, we multiply by the ratio of how far they moved with respect to the screen size 
        // available size of the scroller.
        
        // allow 0% faster if they used everything
        const RATIO_TO_USE:Number = 1.0;
        
		// if off screen for some reason, let's end scrolling:
		if (!scroller.stage)
		{
			// don't do anything
			scrollEndEvent = new TouchInteractionEvent(TouchInteractionEvent.TOUCH_INTERACTION_END, true);
			scrollEndEvent.relatedObject = scroller;
			scrollEndEvent.reason = TouchInteractionReason.SCROLL;
			dispatchBubblingEventOnMouseDownedDisplayObject(scrollEndEvent);
			return;
		}
		
        // for the max size, we couldn't decide between using screen width/height or 
        // scroller width/height, so we're using a weighted average for it
        var widthToUseForRatio:Number = (2*scroller.width + scroller.stage.stageWidth)/3;
        var heightToUseForRatio:Number = (2*scroller.height + scroller.stage.stageHeight)/3;
        var lastMouseEventPoint:Point = mouseEventCoordinatesHistory[endIndex];
        var movedRatio:Point = new Point(Math.abs(RATIO_TO_USE*lastMouseEventPoint.x/widthToUseForRatio), Math.abs(RATIO_TO_USE*lastMouseEventPoint.y/heightToUseForRatio));

        // calculate the last velocity and make sure there was no pause that occurred
        var indexBeforeLast:int = ((mouseEventLength - 2) % EVENT_HISTORY_LENGTH);

		dispatchBubblingEventOnMouseDownedDisplayObject(scrollEndEvent);
    }
    
}
    
import spark.effects.easing.EaseInOutBase;
    
/**
 *  @private
 *  A custom ease-out-only easer class which animates along a specified 
 *  portion of an exponential curve.  
 */
class PartialExponentialCurve extends EaseInOutBase
{
    public function PartialExponentialCurve(exponent:Number,xscale:Number)
    {
        super(0);
        _exponent = exponent;
        _xscale = xscale;
        _ymult = 1 / (1 - Math.pow(1 - _xscale,_exponent));
    }
    
    override protected function easeOut(fraction:Number):Number
    {
        return _ymult * (1 - Math.pow(1 - fraction*_xscale, _exponent)); 
    }
    private var _xscale:Number;
    private var _ymult:Number;
    private var _exponent:Number;
}

