text: /*
  	"Device Motion" and "Shake" event proxy.
  	----------------------------------------------------
  	http://developer.android.com/reference/android/hardware/SensorEvent.html#values
  	----------------------------------------------------
  	Event.add(window, "shake", function(event, self) {});
  	Event.add(window, "devicemotion", function(event, self) {
  		console.log(self.acceleration, self.accelerationIncludingGravity);
  	});
  */
  
  if (typeof(Event) === "undefined") var Event = {};
  if (typeof(Event.proxy) === "undefined") Event.proxy = {};
  
  Event.proxy = (function(root) { "use strict";
  
  root.shake = function(conf) {
  	// Externally accessible data.
  	var self = {
  		gesture: "devicemotion",
  		acceleration: {},
  		accelerationIncludingGravity: {},
  		target: conf.target,
  		listener: conf.listener,
  		remove: function() {
  			window.removeEventListener('devicemotion', onDeviceMotion, false);
  		}
  	};
  	// Setting up local variables.
  	var threshold = 4; // Gravitational threshold.
  	var timeout = 1000; // Timeout between shake events.
  	var timeframe = 200; // Time between shakes.
  	var shakes = 3; // Minimum shakes to trigger event.
  	var lastShake = (new Date).getTime();
  	var gravity = { x: 0, y: 0, z: 0 };
  	var delta = {
  		x: { count: 0, value: 0 },
  		y: { count: 0, value: 0 },
  		z: { count: 0, value: 0 }
  	};
  	// Tracking the events.
  	var onDeviceMotion = function(e) {
  		var alpha = 0.8; // Low pass filter.
  		var o = e.accelerationIncludingGravity;
  		gravity.x = alpha * gravity.x + (1 - alpha) * o.x;
  		gravity.y = alpha * gravity.y + (1 - alpha) * o.y;
  		gravity.z = alpha * gravity.z + (1 - alpha) * o.z; 
  		self.accelerationIncludingGravity = gravity;
  		self.acceleration.x = o.x - gravity.x;
  		self.acceleration.y = o.y - gravity.y;
  		self.acceleration.z = o.z - gravity.z;
  		///
  		if (conf.gesture === "devicemotion") {
  			conf.listener(e, self);
  			return;
  		} 
  		var data = "xyz";
  		var now = (new Date).getTime();
  		for (var n = 0, length = data.length; n < length; n ++) {
  			var letter = data[n];
  			var ACCELERATION = self.acceleration[letter];
  			var DELTA = delta[letter];
  			var abs = Math.abs(ACCELERATION);
  			/// Check whether another shake event was recently registered.
  			if (now - lastShake < timeout) continue;
  			/// Check whether delta surpasses threshold.
  			if (abs > threshold) {
  				var idx = now * ACCELERATION / abs;
  				var span = Math.abs(idx + DELTA.value);
  				// Check whether last delta was registered within timeframe.
  				if (DELTA.value && span < timeframe) {
  					DELTA.value = idx;
  					DELTA.count ++;
  					// Check whether delta count has enough shakes.
  					if (DELTA.count === shakes) {
  						conf.listener(e, self);
  						// Reset tracking.
  						lastShake = now;
  						DELTA.value = 0;
  						DELTA.count = 0;
  					}
  				} else {
  					// Track first shake.
  					DELTA.value = idx;
  					DELTA.count = 1;
  				}
  			}
  		}
  	};
  	// Attach events.
  	if (!window.addEventListener) return;
  	window.addEventListener('devicemotion', onDeviceMotion, false);
  	// Return this object.
  	return self;
  };
  
  Event.Gesture = Event.Gesture || {};
  Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {};
  Event.Gesture._gestureHandlers.shake = root.shake;
  
  return root;
  
  })(Event.proxy);