text: /*! 
   * jquery.event.drop - v 2.2
   * Copyright (c) 2010 Three Dub Media - http://threedubmedia.com
   * Open Source MIT License - http://threedubmedia.com/code/license
   */
  // Created: 2008-06-04 
  // Updated: 2012-05-21
  // REQUIRES: jquery 1.7.x, event.drag 2.2
  
  ;(function($){ // secure $ jQuery alias
  
  // Events: drop, dropstart, dropend
  
  // add the jquery instance method
  $.fn.drop = function( str, arg, opts ){
  	// figure out the event type
  	var type = typeof str == "string" ? str : "",
  	// figure out the event handler...
  	fn = $.isFunction( str ) ? str : $.isFunction( arg ) ? arg : null;
  	// fix the event type
  	if ( type.indexOf("drop") !== 0 ) 
  		type = "drop"+ type;
  	// were options passed
  	opts = ( str == fn ? arg : opts ) || {};
  	// trigger or bind event handler
  	return fn ? this.bind( type, opts, fn ) : this.trigger( type );
  };
  
  // DROP MANAGEMENT UTILITY
  // returns filtered drop target elements, caches their positions
  $.drop = function( opts ){ 
  	opts = opts || {};
  	// safely set new options...
  	drop.multi = opts.multi === true ? Infinity : 
  		opts.multi === false ? 1 : !isNaN( opts.multi ) ? opts.multi : drop.multi;
  	drop.delay = opts.delay || drop.delay;
  	drop.tolerance = $.isFunction( opts.tolerance ) ? opts.tolerance : 
  		opts.tolerance === null ? null : drop.tolerance;
  	drop.mode = opts.mode || drop.mode || 'intersect';
  };
  
  // local refs (increase compression)
  var $event = $.event, 
  $special = $event.special,
  // configure the drop special event
  drop = $.event.special.drop = {
  
  	// these are the default settings
  	multi: 1, // allow multiple drop winners per dragged element
  	delay: 20, // async timeout delay
  	mode: 'overlap', // drop tolerance mode
  
  	// internal cache
  	targets: [], 
  
  	// the key name for stored drop data
  	datakey: "dropdata",
  
  	// prevent bubbling for better performance
  	noBubble: true,
  
  	// count bound related events
  	add: function( obj ){ 
  		// read the interaction data
  		var data = $.data( this, drop.datakey );
  		// count another realted event
  		data.related += 1;
  	},
  
  	// forget unbound related events
  	remove: function(){
  		$.data( this, drop.datakey ).related -= 1;
  	},
  
  	// configure the interactions
  	setup: function(){
  		// check for related events
  		if ( $.data( this, drop.datakey ) ) 
  			return;
  		// initialize the drop element data
  		var data = { 
  			related: 0,
  			active: [],
  			anyactive: 0,
  			winner: 0,
  			location: {}
  		};
  		// store the drop data on the element
  		$.data( this, drop.datakey, data );
  		// store the drop target in internal cache
  		drop.targets.push( this );
  	},
  
  	// destroy the configure interaction	
  	teardown: function(){ 
  		var data = $.data( this, drop.datakey ) || {};
  		// check for related events
  		if ( data.related ) 
  			return;
  		// remove the stored data
  		$.removeData( this, drop.datakey );
  		// reference the targeted element
  		var element = this;
  		// remove from the internal cache
  		drop.targets = $.grep( drop.targets, function( target ){ 
  			return ( target !== element ); 
  		});
  	},
  
  	// shared event handler
  	handler: function( event, dd ){ 
  		// local vars
  		var results, $targets;
  		// make sure the right data is available
  		if ( !dd ) 
  			return;
  		// handle various events
  		switch ( event.type ){
  			// draginit, from $.event.special.drag
  			case 'mousedown': // DROPINIT >>
  			case 'touchstart': // DROPINIT >>
  				// collect and assign the drop targets
  				$targets =  $( drop.targets );
  				if ( typeof dd.drop == "string" )
  					$targets = $targets.filter( dd.drop );
  				// reset drop data winner properties
  				$targets.each(function(){
  					var data = $.data( this, drop.datakey );
  					data.active = [];
  					data.anyactive = 0;
  					data.winner = 0;
  				});
  				// set available target elements
  				dd.droppable = $targets;
  				// activate drop targets for the initial element being dragged
  				$special.drag.hijack( event, "dropinit", dd ); 
  				break;
  			// drag, from $.event.special.drag
  			case 'mousemove': // TOLERATE >>
  			case 'touchmove': // TOLERATE >>
  				drop.event = event; // store the mousemove event
  				if ( !drop.timer )
  					// monitor drop targets
  					drop.tolerate( dd ); 
  				break;
  			// dragend, from $.event.special.drag
  			case 'mouseup': // DROP >> DROPEND >>
  			case 'touchend': // DROP >> DROPEND >>
  				drop.timer = clearTimeout( drop.timer ); // delete timer	
  				if ( dd.propagates ){
  					$special.drag.hijack( event, "drop", dd ); 
  					$special.drag.hijack( event, "dropend", dd ); 
  				}
  				break;
  
  		}
  	},
  
  	// returns the location positions of an element
  	locate: function( elem, index ){ 
  		var data = $.data( elem, drop.datakey ),
  		$elem = $( elem ), 
  		posi = $elem.offset() || {}, 
  		height = $elem.outerHeight(), 
  		width = $elem.outerWidth(),
  		location = { 
  			elem: elem, 
  			width: width, 
  			height: height,
  			top: posi.top, 
  			left: posi.left, 
  			right: posi.left + width, 
  			bottom: posi.top + height
  		};
  		// drag elements might not have dropdata
  		if ( data ){
  			data.location = location;
  			data.index = index;
  			data.elem = elem;
  		}
  		return location;
  	},
  
  	// test the location positions of an element against another OR an X,Y coord
  	contains: function( target, test ){ // target { location } contains test [x,y] or { location }
  		return ( ( test[0] || test.left ) >= target.left && ( test[0] || test.right ) <= target.right
  			&& ( test[1] || test.top ) >= target.top && ( test[1] || test.bottom ) <= target.bottom ); 
  	},
  
  	// stored tolerance modes
  	modes: { // fn scope: "$.event.special.drop" object 
  		// target with mouse wins, else target with most overlap wins
  		'intersect': function( event, proxy, target ){
  			return this.contains( target, [ event.pageX, event.pageY ] ) ? // check cursor
  				1e9 : this.modes.overlap.apply( this, arguments ); // check overlap
  		},
  		// target with most overlap wins	
  		'overlap': function( event, proxy, target ){
  			// calculate the area of overlap...
  			return Math.max( 0, Math.min( target.bottom, proxy.bottom ) - Math.max( target.top, proxy.top ) )
  				* Math.max( 0, Math.min( target.right, proxy.right ) - Math.max( target.left, proxy.left ) );
  		},
  		// proxy is completely contained within target bounds	
  		'fit': function( event, proxy, target ){
  			return this.contains( target, proxy ) ? 1 : 0;
  		},
  		// center of the proxy is contained within target bounds	
  		'middle': function( event, proxy, target ){
  			return this.contains( target, [ proxy.left + proxy.width * .5, proxy.top + proxy.height * .5 ] ) ? 1 : 0;
  		}
  	},	
  
  	// sort drop target cache by by winner (dsc), then index (asc)
  	sort: function( a, b ){
  		return ( b.winner - a.winner ) || ( a.index - b.index );
  	},
  
  	// async, recursive tolerance execution
  	tolerate: function( dd ){		
  		// declare local refs
  		var i, drp, drg, data, arr, len, elem,
  		// interaction iteration variables
  		x = 0, ia, end = dd.interactions.length,
  		// determine the mouse coords
  		xy = [ drop.event.pageX, drop.event.pageY ],
  		// custom or stored tolerance fn
  		tolerance = drop.tolerance || drop.modes[ drop.mode ];
  		// go through each passed interaction...
  		do if ( ia = dd.interactions[x] ){
  			// check valid interaction
  			if ( !ia )
  				return; 
  			// initialize or clear the drop data
  			ia.drop = [];
  			// holds the drop elements
  			arr = []; 
  			len = ia.droppable.length;
  			// determine the proxy location, if needed
  			if ( tolerance )
  				drg = drop.locate( ia.proxy ); 
  			// reset the loop
  			i = 0;
  			// loop each stored drop target
  			do if ( elem = ia.droppable[i] ){ 
  				data = $.data( elem, drop.datakey );
  				drp = data.location;
  				if ( !drp ) continue;
  				// find a winner: tolerance function is defined, call it
  				data.winner = tolerance ? tolerance.call( drop, drop.event, drg, drp ) 
  					// mouse position is always the fallback
  					: drop.contains( drp, xy ) ? 1 : 0; 
  				arr.push( data );	
  			} while ( ++i < len ); // loop 
  			// sort the drop targets
  			arr.sort( drop.sort );			
  			// reset the loop
  			i = 0;
  			// loop through all of the targets again
  			do if ( data = arr[ i ] ){
  				// winners...
  				if ( data.winner && ia.drop.length < drop.multi ){
  					// new winner... dropstart
  					if ( !data.active[x] && !data.anyactive ){
  						// check to make sure that this is not prevented
  						if ( $special.drag.hijack( drop.event, "dropstart", dd, x, data.elem )[0] !== false ){ 	
  							data.active[x] = 1;
  							data.anyactive += 1;
  						}
  						// if false, it is not a winner
  						else
  							data.winner = 0;
  					}
  					// if it is still a winner
  					if ( data.winner )
  						ia.drop.push( data.elem );
  				}
  				// losers... 
  				else if ( data.active[x] && data.anyactive == 1 ){
  					// former winner... dropend
  					$special.drag.hijack( drop.event, "dropend", dd, x, data.elem ); 
  					data.active[x] = 0;
  					data.anyactive -= 1;
  				}
  			} while ( ++i < len ); // loop 		
  		} while ( ++x < end ) // loop
  		// check if the mouse is still moving or is idle
  		if ( drop.last && xy[0] == drop.last.pageX && xy[1] == drop.last.pageY ) 
  			delete drop.timer; // idle, don't recurse
  		else  // recurse
  			drop.timer = setTimeout(function(){ 
  				drop.tolerate( dd ); 
  			}, drop.delay );
  		// remember event, to compare idleness
  		drop.last = drop.event; 
  	}
  
  };
  
  // share the same special event configuration with related events...
  $special.dropinit = $special.dropstart = $special.dropend = drop;
  
  })(jQuery); // confine scope	