Index: wp-includes/js/jcrop/jquery.Jcrop.css
===================================================================
--- wp-includes/js/jcrop/jquery.Jcrop.css	(revision 21018)
+++ wp-includes/js/jcrop/jquery.Jcrop.css	(working copy)
@@ -1,35 +1,86 @@
-/* Fixes issue here http://code.google.com/p/jcrop/issues/detail?id=1 */
-.jcrop-holder { text-align: left; }
+/* jquery.Jcrop.css v0.9.10 - MIT License */
 
-.jcrop-vline, .jcrop-hline
+/*
+  The outer-most container in a typical Jcrop instance
+  If you are having difficulty with formatting related to styles
+  on a parent element, place any fixes here or in a like selector
+
+  You can also style this element if you want to add a border, etc
+  A better method for styling can be seen below with .jcrop-light
+  (Add a class to the holder and style elements for that extended class)
+*/
+.jcrop-holder {
+  direction: ltr;
+  text-align: left;
+}
+
+/* These styles define the border lines */
+.jcrop-vline,.jcrop-hline{background:#FFF url(Jcrop.gif) top left repeat;font-size:0;position:absolute;}
+.jcrop-vline{height:100%;width:1px!important;}
+.jcrop-hline{height:1px!important;width:100%;}
+.jcrop-vline.right{right:0;}
+.jcrop-hline.bottom{bottom:0;}
+
+/* Handle style - size is set by Jcrop handleSize option (currently) */
+.jcrop-handle{background-color:#333;border:1px #eee solid;font-size:1px;}
+
+/* This style is used for invisible click targets */
+.jcrop-tracker
 {
-	font-size: 0;
-	position: absolute;
-	background: white url('Jcrop.gif') top left repeat;
+  height: 100%; 
+  width: 100%;
+  -webkit-tap-highlight-color: transparent; /* "turn off" link highlight */
+  -webkit-touch-callout: none;              /* disable callout, image save panel */
+  -webkit-user-select: none;                /* disable cut copy paste */
 }
-.jcrop-vline { height: 100%; width: 1px !important; }
-.jcrop-hline { width: 100%; height: 1px !important; }
-.jcrop-handle {
-	font-size: 1px;
-	width: 7px !important;
-	height: 7px !important;
-	border: 1px #eee solid;
-	background-color: #333;
-	*width: 9px;
-	*height: 9px;
-}
 
-.jcrop-tracker { width: 100%; height: 100%; }
+/* Positioning of handles and drag bars */
+.jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0;}
+.jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px;}
+.jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%;}
+.jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%;}
+.jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0;}
+.jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0;}
+.jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0;}
+.jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px;}
+.jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%;}
+.jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px;}
+.jcrop-dragbar.ord-n{margin-top:-4px;}
+.jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px;}
+.jcrop-dragbar.ord-e{margin-right:-4px;right:0;}
+.jcrop-dragbar.ord-w{margin-left:-4px;}
 
-.custom .jcrop-vline,
-.custom .jcrop-hline
+/* The "jcrop-light" class/extension */
+.jcrop-light .jcrop-vline,.jcrop-light .jcrop-hline
 {
-	background: yellow;
+	background:#FFF;
+	filter:Alpha(opacity=70)!important;
+	opacity:.70!important;
 }
-.custom .jcrop-handle
+.jcrop-light .jcrop-handle
 {
-	border-color: black;
-	background-color: #C7BB00;
-	-moz-border-radius: 3px;
-	-webkit-border-radius: 3px;
+	-moz-border-radius:3px;
+	-webkit-border-radius:3px;
+	background-color:#000;
+	border-color:#FFF;
+	border-radius:3px;
 }
+
+/* The "jcrop-dark" class/extension */
+.jcrop-dark .jcrop-vline,.jcrop-dark .jcrop-hline
+{
+	background:#000;
+	filter:Alpha(opacity=70)!important;
+	opacity:.7!important;
+}
+.jcrop-dark .jcrop-handle
+{
+	-moz-border-radius:3px;
+	-webkit-border-radius:3px;
+	background-color:#FFF;
+	border-color:#000;
+	border-radius:3px;
+}
+
+/* Fix for twitter bootstrap et al. */
+.jcrop-holder img,img.jcrop-preview{ max-width: none; }
Index: wp-includes/js/jcrop/jquery.Jcrop.dev.js
===================================================================
--- wp-includes/js/jcrop/jquery.Jcrop.dev.js	(revision 21018)
+++ wp-includes/js/jcrop/jquery.Jcrop.dev.js	(working copy)
@@ -1,8 +1,9 @@
 /**
- * jquery.Jcrop.js v0.9.8
- * jQuery Image Cropping Plugin
- * @author Kelly Hallman <khallman@gmail.com>
- * Copyright (c) 2008-2009 Kelly Hallman - released under MIT License {{{
+ * jquery.Jcrop.js v0.9.10
+ * jQuery Image Cropping Plugin - released under MIT License 
+ * Author: Kelly Hallman <khallman@gmail.com>
+ * http://github.com/tapmodo/Jcrop
+ * Copyright (c) 2008-2012 Tapmodo Interactive LLC {{{
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -12,10 +13,10 @@
  * copies of the Software, and to permit persons to whom the
  * Software is furnished to do so, subject to the following
  * conditions:
-
+ *
  * The above copyright notice and this permission notice shall be
  * included in all copies or substantial portions of the Software.
-
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -24,1174 +25,1671 @@
  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
-
+ *
  * }}}
  */
 
-(function($) {
+(function ($) {
 
-$.Jcrop = function(obj,opt)
-{
-	// Initialization {{{
+  $.Jcrop = function (obj, opt) {
+    var options = $.extend({}, $.Jcrop.defaults),
+        docOffset, lastcurs, ie6mode = false;
 
-	// Sanitize some options {{{
-	var obj = obj, opt = opt;
+    // Internal Methods {{{
+    function px(n) {
+      return n + 'px';
+    }
+    function cssClass(cl) {
+      return options.baseClass + '-' + cl;
+    }
+    function supportsColorFade() {
+      return $.fx.step.hasOwnProperty('backgroundColor');
+    }
+    function getPos(obj) //{{{
+    {
+      var pos = $(obj).offset();
+      return [pos.left, pos.top];
+    }
+    //}}}
+    function mouseAbs(e) //{{{
+    {
+      return [(e.pageX - docOffset[0]), (e.pageY - docOffset[1])];
+    }
+    //}}}
+    function setOptions(opt) //{{{
+    {
+      if (typeof(opt) !== 'object') opt = {};
+      options = $.extend(options, opt);
 
-	if (typeof(obj) !== 'object') obj = $(obj)[0];
-	if (typeof(opt) !== 'object') opt = { };
+      $.each(['onChange','onSelect','onRelease','onDblClick'],function(i,e) {
+        if (typeof(options[e]) !== 'function') options[e] = function () {};
+      });
+    }
+    //}}}
+    function startDragMode(mode, pos) //{{{
+    {
+      docOffset = getPos($img);
+      Tracker.setCursor(mode === 'move' ? mode : mode + '-resize');
 
-	// Some on-the-fly fixes for MSIE...sigh
-	if (!('trackDocument' in opt))
-	{
-		opt.trackDocument = $.browser.msie ? false : true;
-		if ($.browser.msie && $.browser.version.split('.')[0] == '8')
-			opt.trackDocument = true;
-	}
+      if (mode === 'move') {
+        return Tracker.activateHandlers(createMover(pos), doneSelect);
+      }
 
-	if (!('keySupport' in opt))
-			opt.keySupport = $.browser.msie ? false : true;
-		
-	// }}}
-	// Extend the default options {{{
-	var defaults = {
+      var fc = Coords.getFixed();
+      var opp = oppLockCorner(mode);
+      var opc = Coords.getCorner(oppLockCorner(opp));
 
-		// Basic Settings
-		trackDocument:		false,
-		baseClass:			'jcrop',
-		addClass:			null,
+      Coords.setPressed(Coords.getCorner(opp));
+      Coords.setCurrent(opc);
 
-		// Styling Options
-		bgColor:			'black',
-		bgOpacity:			.6,
-		borderOpacity:		.4,
-		handleOpacity:		.5,
+      Tracker.activateHandlers(dragmodeHandler(mode, fc), doneSelect);
+    }
+    //}}}
+    function dragmodeHandler(mode, f) //{{{
+    {
+      return function (pos) {
+        if (!options.aspectRatio) {
+          switch (mode) {
+          case 'e':
+            pos[1] = f.y2;
+            break;
+          case 'w':
+            pos[1] = f.y2;
+            break;
+          case 'n':
+            pos[0] = f.x2;
+            break;
+          case 's':
+            pos[0] = f.x2;
+            break;
+          }
+        } else {
+          switch (mode) {
+          case 'e':
+            pos[1] = f.y + 1;
+            break;
+          case 'w':
+            pos[1] = f.y + 1;
+            break;
+          case 'n':
+            pos[0] = f.x + 1;
+            break;
+          case 's':
+            pos[0] = f.x + 1;
+            break;
+          }
+        }
+        Coords.setCurrent(pos);
+        Selection.update();
+      };
+    }
+    //}}}
+    function createMover(pos) //{{{
+    {
+      var lloc = pos;
+      KeyManager.watchKeys();
 
-		handlePad:			5,
-		handleSize:			9,
-		handleOffset:		5,
-		edgeMargin:			14,
+      return function (pos) {
+        Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]);
+        lloc = pos;
 
-		aspectRatio:		0,
-		keySupport:			true,
-		cornerHandles:		true,
-		sideHandles:		true,
-		drawBorders:		true,
-		dragEdges:			true,
+        Selection.update();
+      };
+    }
+    //}}}
+    function oppLockCorner(ord) //{{{
+    {
+      switch (ord) {
+      case 'n':
+        return 'sw';
+      case 's':
+        return 'nw';
+      case 'e':
+        return 'nw';
+      case 'w':
+        return 'ne';
+      case 'ne':
+        return 'sw';
+      case 'nw':
+        return 'se';
+      case 'se':
+        return 'nw';
+      case 'sw':
+        return 'ne';
+      }
+    }
+    //}}}
+    function createDragger(ord) //{{{
+    {
+      return function (e) {
+        if (options.disabled) {
+          return false;
+        }
+        if ((ord === 'move') && !options.allowMove) {
+          return false;
+        }
+        
+        // Fix position of crop area when dragged the very first time.
+        // Necessary when crop image is in a hidden element when page is loaded.
+        docOffset = getPos($img);
 
-		boxWidth:			0,
-		boxHeight:			0,
+        btndown = true;
+        startDragMode(ord, mouseAbs(e));
+        e.stopPropagation();
+        e.preventDefault();
+        return false;
+      };
+    }
+    //}}}
+    function presize($obj, w, h) //{{{
+    {
+      var nw = $obj.width(),
+          nh = $obj.height();
+      if ((nw > w) && w > 0) {
+        nw = w;
+        nh = (w / $obj.width()) * $obj.height();
+      }
+      if ((nh > h) && h > 0) {
+        nh = h;
+        nw = (h / $obj.height()) * $obj.width();
+      }
+      xscale = $obj.width() / nw;
+      yscale = $obj.height() / nh;
+      $obj.width(nw).height(nh);
+    }
+    //}}}
+    function unscale(c) //{{{
+    {
+      return {
+        x: c.x * xscale,
+        y: c.y * yscale,
+        x2: c.x2 * xscale,
+        y2: c.y2 * yscale,
+        w: c.w * xscale,
+        h: c.h * yscale
+      };
+    }
+    //}}}
+    function doneSelect(pos) //{{{
+    {
+      var c = Coords.getFixed();
+      if ((c.w > options.minSelect[0]) && (c.h > options.minSelect[1])) {
+        Selection.enableHandles();
+        Selection.done();
+      } else {
+        Selection.release();
+      }
+      Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
+    }
+    //}}}
+    function newSelection(e) //{{{
+    {
+      if (options.disabled) {
+        return false;
+      }
+      if (!options.allowSelect) {
+        return false;
+      }
+      btndown = true;
+      docOffset = getPos($img);
+      Selection.disableHandles();
+      Tracker.setCursor('crosshair');
+      var pos = mouseAbs(e);
+      Coords.setPressed(pos);
+      Selection.update();
+      Tracker.activateHandlers(selectDrag, doneSelect);
+      KeyManager.watchKeys();
 
-		boundary:			8,
-		animationDelay:		20,
-		swingSpeed:			3,
+      e.stopPropagation();
+      e.preventDefault();
+      return false;
+    }
+    //}}}
+    function selectDrag(pos) //{{{
+    {
+      Coords.setCurrent(pos);
+      Selection.update();
+    }
+    //}}}
+    function newTracker() //{{{
+    {
+      var trk = $('<div></div>').addClass(cssClass('tracker'));
+      if ($.browser.msie) {
+        trk.css({
+          opacity: 0,
+          backgroundColor: 'white'
+        });
+      }
+      return trk;
+    }
+    //}}}
 
-		allowSelect:		true,
-		allowMove:			true,
-		allowResize:		true,
+    // }}}
+    // Initialization {{{
+    // Sanitize some options {{{
+    if ($.browser.msie && ($.browser.version.split('.')[0] === '6')) {
+      ie6mode = true;
+    }
+    if (typeof(obj) !== 'object') {
+      obj = $(obj)[0];
+    }
+    if (typeof(opt) !== 'object') {
+      opt = {};
+    }
+    // }}}
+    setOptions(opt);
+    // Initialize some jQuery objects {{{
+    // The values are SET on the image(s) for the interface
+    // If the original image has any of these set, they will be reset
+    // However, if you destroy() the Jcrop instance the original image's
+    // character in the DOM will be as you left it.
+    var img_css = {
+      border: 'none',
+      visibility: 'visible',
+      margin: 0,
+      padding: 0,
+      position: 'absolute',
+      top: 0,
+      left: 0
+    };
 
-		minSelect:			[ 0, 0 ],
-		maxSize:			[ 0, 0 ],
-		minSize:			[ 0, 0 ],
+    var $origimg = $(obj),
+      img_mode = true;
 
-		// Callbacks / Event Handlers
-		onChange: function() { },
-		onSelect: function() { }
+    if (obj.tagName == 'IMG') {
+      // Fix size of crop image.
+      // Necessary when crop image is within a hidden element when page is loaded.
+      if ($origimg[0].width != 0 && $origimg[0].height != 0) {
+        // Obtain dimensions from contained img element.
+        $origimg.width($origimg[0].width);
+        $origimg.height($origimg[0].height);
+      } else {
+        // Obtain dimensions from temporary image in case the original is not loaded yet (e.g. IE 7.0). 
+        var tempImage = new Image();
+        tempImage.src = $origimg[0].src;
+        $origimg.width(tempImage.width);
+        $origimg.height(tempImage.height);
+      } 
 
-	};
-	var options = defaults;
-	setOptions(opt);
+      var $img = $origimg.clone().removeAttr('id').css(img_css).show();
 
-	// }}}
-	// Initialize some jQuery objects {{{
+      $img.width($origimg.width());
+      $img.height($origimg.height());
+      $origimg.after($img).hide();
 
-	var $origimg = $(obj);
-	var $img = $origimg.clone().removeAttr('id').css({ position: 'absolute' });
+    } else {
+      $img = $origimg.css(img_css).show();
+      img_mode = false;
+      if (options.shade === null) { options.shade = true; }
+    }
 
-	$img.width($origimg.width());
-	$img.height($origimg.height());
-	$origimg.after($img).hide();
+    presize($img, options.boxWidth, options.boxHeight);
 
-	presize($img,options.boxWidth,options.boxHeight);
+    var boundx = $img.width(),
+        boundy = $img.height(),
+        
+        
+        $div = $('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({
+        position: 'relative',
+        backgroundColor: options.bgColor
+      }).insertAfter($origimg).append($img);
 
-	var boundx = $img.width(),
-		boundy = $img.height(),
+    if (options.addClass) {
+      $div.addClass(options.addClass);
+    }
 
-		$div = $('<div />')
-			.width(boundx).height(boundy)
-			.addClass(cssClass('holder'))
-			.css({
-				position: 'relative',
-				backgroundColor: options.bgColor
-			}).insertAfter($origimg).append($img);
-	;
-	
-	if (options.addClass) $div.addClass(options.addClass);
-	//$img.wrap($div);
+    var $img2 = $('<div />'),
 
-	var $img2 = $('<img />')/*{{{*/
-			.attr('src',$img.attr('src'))
-			.css('position','absolute')
-			.width(boundx).height(boundy)
-	;/*}}}*/
-	var $img_holder = $('<div />')/*{{{*/
-		.width(pct(100)).height(pct(100))
-		.css({
-			zIndex: 310,
-			position: 'absolute',
-			overflow: 'hidden'
-		})
-		.append($img2)
-	;/*}}}*/
-	var $hdl_holder = $('<div />')/*{{{*/
-		.width(pct(100)).height(pct(100))
-		.css('zIndex',320);
-	/*}}}*/
-	var $sel = $('<div />')/*{{{*/
-		.css({
-			position: 'absolute',
-			zIndex: 300
-		})
-		.insertBefore($img)
-		.append($img_holder,$hdl_holder)
-	;/*}}}*/
+        $img_holder = $('<div />') 
+        .width('100%').height('100%').css({
+          zIndex: 310,
+          position: 'absolute',
+          overflow: 'hidden'
+        }),
 
-	var bound = options.boundary;
-	var $trk = newTracker().width(boundx+(bound*2)).height(boundy+(bound*2))
-		.css({ position: 'absolute', top: px(-bound), left: px(-bound), zIndex: 290 })
-		.mousedown(newSelection);	
-	
-	/* }}} */
-	// Set more variables {{{
+        $hdl_holder = $('<div />') 
+        .width('100%').height('100%').css('zIndex', 320), 
 
-	var xlimit, ylimit, xmin, ymin;
-	var xscale, yscale, enabled = true;
-	var docOffset = getPos($img),
-		// Internal states
-		btndown, lastcurs, dimmed, animating,
-		shift_down;
+        $sel = $('<div />') 
+        .css({
+          position: 'absolute',
+          zIndex: 600
+        }).dblclick(function(){
+          var c = Coords.getFixed();
+          options.onDblClick.call(api,c);
+        }).insertBefore($img).append($img_holder, $hdl_holder); 
 
-	// }}}
-		
+    if (img_mode) {
 
-		// }}}
-	// Internal Modules {{{
+      $img2 = $('<img />')
+          .attr('src', $img.attr('src')).css(img_css).width(boundx).height(boundy),
 
-	var Coords = function()/*{{{*/
-	{
-		var x1 = 0, y1 = 0, x2 = 0, y2 = 0, ox, oy;
+      $img_holder.append($img2);
 
-		function setPressed(pos)/*{{{*/
-		{
-			var pos = rebound(pos);
-			x2 = x1 = pos[0];
-			y2 = y1 = pos[1];
-		};
-		/*}}}*/
-		function setCurrent(pos)/*{{{*/
-		{
-			var pos = rebound(pos);
-			ox = pos[0] - x2;
-			oy = pos[1] - y2;
-			x2 = pos[0];
-			y2 = pos[1];
-		};
-		/*}}}*/
-		function getOffset()/*{{{*/
-		{
-			return [ ox, oy ];
-		};
-		/*}}}*/
-		function moveOffset(offset)/*{{{*/
-		{
-			var ox = offset[0], oy = offset[1];
+    }
 
-			if (0 > x1 + ox) ox -= ox + x1;
-			if (0 > y1 + oy) oy -= oy + y1;
+    if (ie6mode) {
+      $sel.css({
+        overflowY: 'hidden'
+      });
+    }
 
-			if (boundy < y2 + oy) oy += boundy - (y2 + oy);
-			if (boundx < x2 + ox) ox += boundx - (x2 + ox);
+    var bound = options.boundary;
+    var $trk = newTracker().width(boundx + (bound * 2)).height(boundy + (bound * 2)).css({
+      position: 'absolute',
+      top: px(-bound),
+      left: px(-bound),
+      zIndex: 290
+    }).mousedown(newSelection);
 
-			x1 += ox;
-			x2 += ox;
-			y1 += oy;
-			y2 += oy;
-		};
-		/*}}}*/
-		function getCorner(ord)/*{{{*/
-		{
-			var c = getFixed();
-			switch(ord)
-			{
-				case 'ne': return [ c.x2, c.y ];
-				case 'nw': return [ c.x, c.y ];
-				case 'se': return [ c.x2, c.y2 ];
-				case 'sw': return [ c.x, c.y2 ];
-			}
-		};
-		/*}}}*/
-		function getFixed()/*{{{*/
-		{
-			if (!options.aspectRatio) return getRect();
-			// This function could use some optimization I think...
-			var aspect = options.aspectRatio,
-				min_x = options.minSize[0]/xscale, 
-				min_y = options.minSize[1]/yscale,
-				max_x = options.maxSize[0]/xscale, 
-				max_y = options.maxSize[1]/yscale,
-				rw = x2 - x1,
-				rh = y2 - y1,
-				rwa = Math.abs(rw),
-				rha = Math.abs(rh),
-				real_ratio = rwa / rha,
-				xx, yy
-			;
-			if (max_x == 0) { max_x = boundx * 10 }
-			if (max_y == 0) { max_y = boundy * 10 }
-			if (real_ratio < aspect)
-			{
-				yy = y2;
-				w = rha * aspect;
-				xx = rw < 0 ? x1 - w : w + x1;
+    /* }}} */
+    // Set more variables {{{
+    var bgcolor = options.bgColor,
+        bgopacity = options.bgOpacity,
+        xlimit, ylimit, xmin, ymin, xscale, yscale, enabled = true,
+        btndown, animating, shift_down;
 
-				if (xx < 0)
-				{
-					xx = 0;
-					h = Math.abs((xx - x1) / aspect);
-					yy = rh < 0 ? y1 - h: h + y1;
-				}
-				else if (xx > boundx)
-				{
-					xx = boundx;
-					h = Math.abs((xx - x1) / aspect);
-					yy = rh < 0 ? y1 - h : h + y1;
-				}
-			}
-			else
-			{
-				xx = x2;
-				h = rwa / aspect;
-				yy = rh < 0 ? y1 - h : y1 + h;
-				if (yy < 0)
-				{
-					yy = 0;
-					w = Math.abs((yy - y1) * aspect);
-					xx = rw < 0 ? x1 - w : w + x1;
-				}
-				else if (yy > boundy)
-				{
-					yy = boundy;
-					w = Math.abs(yy - y1) * aspect;
-					xx = rw < 0 ? x1 - w : w + x1;
-				}
-			}
+    docOffset = getPos($img);
+    // }}}
+    // }}}
+    // Internal Modules {{{
+    // Touch Module {{{ 
+    var Touch = (function () {
+      // Touch support detection function adapted (under MIT License)
+      // from code by Jeffrey Sambells - http://github.com/iamamused/
+      function hasTouchSupport() {
+        var support = {},
+            events = ['touchstart', 'touchmove', 'touchend'],
+            el = document.createElement('div'), i;
 
-			// Magic %-)
-			if(xx > x1) { // right side
-			  if(xx - x1 < min_x) {
-				xx = x1 + min_x;
-			  } else if (xx - x1 > max_x) {
-				xx = x1 + max_x;
-			  }
-			  if(yy > y1) {
-				yy = y1 + (xx - x1)/aspect;
-			  } else {
-				yy = y1 - (xx - x1)/aspect;
-			  }
-			} else if (xx < x1) { // left side
-			  if(x1 - xx < min_x) {
-				xx = x1 - min_x
-			  } else if (x1 - xx > max_x) {
-				xx = x1 - max_x;
-			  }
-			  if(yy > y1) {
-				yy = y1 + (x1 - xx)/aspect;
-			  } else {
-				yy = y1 - (x1 - xx)/aspect;
-			  }
-			}
+        try {
+          for(i=0; i<events.length; i++) {
+            var eventName = events[i];
+            eventName = 'on' + eventName;
+            var isSupported = (eventName in el);
+            if (!isSupported) {
+              el.setAttribute(eventName, 'return;');
+              isSupported = typeof el[eventName] == 'function';
+            }
+            support[events[i]] = isSupported;
+          }
+          return support.touchstart && support.touchend && support.touchmove;
+        }
+        catch(err) {
+          return false;
+        }
+      }
 
-			if(xx < 0) {
-				x1 -= xx;
-				xx = 0;
-			} else  if (xx > boundx) {
-				x1 -= xx - boundx;
-				xx = boundx;
-			}
+      function detectSupport() {
+        if ((options.touchSupport === true) || (options.touchSupport === false)) return options.touchSupport;
+          else return hasTouchSupport();
+      }
+      return {
+        createDragger: function (ord) {
+          return function (e) {
+            e.pageX = e.originalEvent.changedTouches[0].pageX;
+            e.pageY = e.originalEvent.changedTouches[0].pageY;
+            if (options.disabled) {
+              return false;
+            }
+            if ((ord === 'move') && !options.allowMove) {
+              return false;
+            }
+            btndown = true;
+            startDragMode(ord, mouseAbs(e));
+            e.stopPropagation();
+            e.preventDefault();
+            return false;
+          };
+        },
+        newSelection: function (e) {
+          e.pageX = e.originalEvent.changedTouches[0].pageX;
+          e.pageY = e.originalEvent.changedTouches[0].pageY;
+          return newSelection(e);
+        },
+        isSupported: hasTouchSupport,
+        support: detectSupport()
+      };
+    }());
+    // }}}
+    // Coords Module {{{
+    var Coords = (function () {
+      var x1 = 0,
+          y1 = 0,
+          x2 = 0,
+          y2 = 0,
+          ox, oy;
 
-			if(yy < 0) {
-				y1 -= yy;
-				yy = 0;
-			} else  if (yy > boundy) {
-				y1 -= yy - boundy;
-				yy = boundy;
-			}
+      function setPressed(pos) //{{{
+      {
+        pos = rebound(pos);
+        x2 = x1 = pos[0];
+        y2 = y1 = pos[1];
+      }
+      //}}}
+      function setCurrent(pos) //{{{
+      {
+        pos = rebound(pos);
+        ox = pos[0] - x2;
+        oy = pos[1] - y2;
+        x2 = pos[0];
+        y2 = pos[1];
+      }
+      //}}}
+      function getOffset() //{{{
+      {
+        return [ox, oy];
+      }
+      //}}}
+      function moveOffset(offset) //{{{
+      {
+        var ox = offset[0],
+            oy = offset[1];
 
-			return last = makeObj(flipCoords(x1,y1,xx,yy));
-		};
-		/*}}}*/
-		function rebound(p)/*{{{*/
-		{
-			if (p[0] < 0) p[0] = 0;
-			if (p[1] < 0) p[1] = 0;
+        if (0 > x1 + ox) {
+          ox -= ox + x1;
+        }
+        if (0 > y1 + oy) {
+          oy -= oy + y1;
+        }
 
-			if (p[0] > boundx) p[0] = boundx;
-			if (p[1] > boundy) p[1] = boundy;
+        if (boundy < y2 + oy) {
+          oy += boundy - (y2 + oy);
+        }
+        if (boundx < x2 + ox) {
+          ox += boundx - (x2 + ox);
+        }
 
-			return [ p[0], p[1] ];
-		};
-		/*}}}*/
-		function flipCoords(x1,y1,x2,y2)/*{{{*/
-		{
-			var xa = x1, xb = x2, ya = y1, yb = y2;
-			if (x2 < x1)
-			{
-				xa = x2;
-				xb = x1;
-			}
-			if (y2 < y1)
-			{
-				ya = y2;
-				yb = y1;
-			}
-			return [ Math.round(xa), Math.round(ya), Math.round(xb), Math.round(yb) ];
-		};
-		/*}}}*/
-		function getRect()/*{{{*/
-		{
-			var xsize = x2 - x1;
-			var ysize = y2 - y1;
+        x1 += ox;
+        x2 += ox;
+        y1 += oy;
+        y2 += oy;
+      }
+      //}}}
+      function getCorner(ord) //{{{
+      {
+        var c = getFixed();
+        switch (ord) {
+        case 'ne':
+          return [c.x2, c.y];
+        case 'nw':
+          return [c.x, c.y];
+        case 'se':
+          return [c.x2, c.y2];
+        case 'sw':
+          return [c.x, c.y2];
+        }
+      }
+      //}}}
+      function getFixed() //{{{
+      {
+        if (!options.aspectRatio) {
+          return getRect();
+        }
+        // This function could use some optimization I think...
+        var aspect = options.aspectRatio,
+            min_x = options.minSize[0] / xscale,
+            
+            
+            //min_y = options.minSize[1]/yscale,
+            max_x = options.maxSize[0] / xscale,
+            max_y = options.maxSize[1] / yscale,
+            rw = x2 - x1,
+            rh = y2 - y1,
+            rwa = Math.abs(rw),
+            rha = Math.abs(rh),
+            real_ratio = rwa / rha,
+            xx, yy, w, h;
 
-			if (xlimit && (Math.abs(xsize) > xlimit))
-				x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit);
-			if (ylimit && (Math.abs(ysize) > ylimit))
-				y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit);
+        if (max_x === 0) {
+          max_x = boundx * 10;
+        }
+        if (max_y === 0) {
+          max_y = boundy * 10;
+        }
+        if (real_ratio < aspect) {
+          yy = y2;
+          w = rha * aspect;
+          xx = rw < 0 ? x1 - w : w + x1;
 
-			if (ymin && (Math.abs(ysize) < ymin))
-				y2 = (ysize > 0) ? (y1 + ymin) : (y1 - ymin);
-			if (xmin && (Math.abs(xsize) < xmin))
-				x2 = (xsize > 0) ? (x1 + xmin) : (x1 - xmin);
+          if (xx < 0) {
+            xx = 0;
+            h = Math.abs((xx - x1) / aspect);
+            yy = rh < 0 ? y1 - h : h + y1;
+          } else if (xx > boundx) {
+            xx = boundx;
+            h = Math.abs((xx - x1) / aspect);
+            yy = rh < 0 ? y1 - h : h + y1;
+          }
+        } else {
+          xx = x2;
+          h = rwa / aspect;
+          yy = rh < 0 ? y1 - h : y1 + h;
+          if (yy < 0) {
+            yy = 0;
+            w = Math.abs((yy - y1) * aspect);
+            xx = rw < 0 ? x1 - w : w + x1;
+          } else if (yy > boundy) {
+            yy = boundy;
+            w = Math.abs(yy - y1) * aspect;
+            xx = rw < 0 ? x1 - w : w + x1;
+          }
+        }
 
-			if (x1 < 0) { x2 -= x1; x1 -= x1; }
-			if (y1 < 0) { y2 -= y1; y1 -= y1; }
-			if (x2 < 0) { x1 -= x2; x2 -= x2; }
-			if (y2 < 0) { y1 -= y2; y2 -= y2; }
-			if (x2 > boundx) { var delta = x2 - boundx; x1 -= delta; x2 -= delta; }
-			if (y2 > boundy) { var delta = y2 - boundy; y1 -= delta; y2 -= delta; }
-			if (x1 > boundx) { var delta = x1 - boundy; y2 -= delta; y1 -= delta; }
-			if (y1 > boundy) { var delta = y1 - boundy; y2 -= delta; y1 -= delta; }
+        // Magic %-)
+        if (xx > x1) { // right side
+          if (xx - x1 < min_x) {
+            xx = x1 + min_x;
+          } else if (xx - x1 > max_x) {
+            xx = x1 + max_x;
+          }
+          if (yy > y1) {
+            yy = y1 + (xx - x1) / aspect;
+          } else {
+            yy = y1 - (xx - x1) / aspect;
+          }
+        } else if (xx < x1) { // left side
+          if (x1 - xx < min_x) {
+            xx = x1 - min_x;
+          } else if (x1 - xx > max_x) {
+            xx = x1 - max_x;
+          }
+          if (yy > y1) {
+            yy = y1 + (x1 - xx) / aspect;
+          } else {
+            yy = y1 - (x1 - xx) / aspect;
+          }
+        }
 
-			return makeObj(flipCoords(x1,y1,x2,y2));
-		};
-		/*}}}*/
-		function makeObj(a)/*{{{*/
-		{
-			return { x: a[0], y: a[1], x2: a[2], y2: a[3],
-				w: a[2] - a[0], h: a[3] - a[1] };
-		};
-		/*}}}*/
+        if (xx < 0) {
+          x1 -= xx;
+          xx = 0;
+        } else if (xx > boundx) {
+          x1 -= xx - boundx;
+          xx = boundx;
+        }
 
-		return {
-			flipCoords: flipCoords,
-			setPressed: setPressed,
-			setCurrent: setCurrent,
-			getOffset: getOffset,
-			moveOffset: moveOffset,
-			getCorner: getCorner,
-			getFixed: getFixed
-		};
-	}();
+        if (yy < 0) {
+          y1 -= yy;
+          yy = 0;
+        } else if (yy > boundy) {
+          y1 -= yy - boundy;
+          yy = boundy;
+        }
 
-	/*}}}*/
-	var Selection = function()/*{{{*/
-	{
-		var start, end, dragmode, awake, hdep = 370;
-		var borders = { };
-		var handle = { };
-		var seehandles = false;
-		var hhs = options.handleOffset;
+        return makeObj(flipCoords(x1, y1, xx, yy));
+      }
+      //}}}
+      function rebound(p) //{{{
+      {
+        if (p[0] < 0) {
+          p[0] = 0;
+        }
+        if (p[1] < 0) {
+          p[1] = 0;
+        }
 
-		/* Insert draggable elements {{{*/
+        if (p[0] > boundx) {
+          p[0] = boundx;
+        }
+        if (p[1] > boundy) {
+          p[1] = boundy;
+        }
 
-		// Insert border divs for outline
-		if (options.drawBorders) {
-			borders = {
-					top: insertBorder('hline')
-						.css('top',$.browser.msie?px(-1):px(0)),
-					bottom: insertBorder('hline'),
-					left: insertBorder('vline'),
-					right: insertBorder('vline')
-			};
-		}
+        return [p[0], p[1]];
+      }
+      //}}}
+      function flipCoords(x1, y1, x2, y2) //{{{
+      {
+        var xa = x1,
+            xb = x2,
+            ya = y1,
+            yb = y2;
+        if (x2 < x1) {
+          xa = x2;
+          xb = x1;
+        }
+        if (y2 < y1) {
+          ya = y2;
+          yb = y1;
+        }
+        return [xa, ya, xb, yb];
+      }
+      //}}}
+      function getRect() //{{{
+      {
+        var xsize = x2 - x1,
+            ysize = y2 - y1,
+            delta;
 
-		// Insert handles on edges
-		if (options.dragEdges) {
-			handle.t = insertDragbar('n');
-			handle.b = insertDragbar('s');
-			handle.r = insertDragbar('e');
-			handle.l = insertDragbar('w');
-		}
+        if (xlimit && (Math.abs(xsize) > xlimit)) {
+          x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit);
+        }
+        if (ylimit && (Math.abs(ysize) > ylimit)) {
+          y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit);
+        }
 
-		// Insert side handles
-		options.sideHandles &&
-			createHandles(['n','s','e','w']);
+        if (ymin / yscale && (Math.abs(ysize) < ymin / yscale)) {
+          y2 = (ysize > 0) ? (y1 + ymin / yscale) : (y1 - ymin / yscale);
+        }
+        if (xmin / xscale && (Math.abs(xsize) < xmin / xscale)) {
+          x2 = (xsize > 0) ? (x1 + xmin / xscale) : (x1 - xmin / xscale);
+        }
 
-		// Insert corner handles
-		options.cornerHandles &&
-			createHandles(['sw','nw','ne','se']);
+        if (x1 < 0) {
+          x2 -= x1;
+          x1 -= x1;
+        }
+        if (y1 < 0) {
+          y2 -= y1;
+          y1 -= y1;
+        }
+        if (x2 < 0) {
+          x1 -= x2;
+          x2 -= x2;
+        }
+        if (y2 < 0) {
+          y1 -= y2;
+          y2 -= y2;
+        }
+        if (x2 > boundx) {
+          delta = x2 - boundx;
+          x1 -= delta;
+          x2 -= delta;
+        }
+        if (y2 > boundy) {
+          delta = y2 - boundy;
+          y1 -= delta;
+          y2 -= delta;
+        }
+        if (x1 > boundx) {
+          delta = x1 - boundy;
+          y2 -= delta;
+          y1 -= delta;
+        }
+        if (y1 > boundy) {
+          delta = y1 - boundy;
+          y2 -= delta;
+          y1 -= delta;
+        }
 
-		/*}}}*/
-		// Private Methods
-		function insertBorder(type)/*{{{*/
-		{
-			var jq = $('<div />')
-				.css({position: 'absolute', opacity: options.borderOpacity })
-				.addClass(cssClass(type));
-			$img_holder.append(jq);
-			return jq;
-		};
-		/*}}}*/
-		function dragDiv(ord,zi)/*{{{*/
-		{
-			var jq = $('<div />')
-				.mousedown(createDragger(ord))
-				.css({
-					cursor: ord+'-resize',
-					position: 'absolute',
-					zIndex: zi 
-				})
-			;
-			$hdl_holder.append(jq);
-			return jq;
-		};
-		/*}}}*/
-		function insertHandle(ord)/*{{{*/
-		{
-			return dragDiv(ord,hdep++)
-				.css({ top: px(-hhs+1), left: px(-hhs+1), opacity: options.handleOpacity })
-				.addClass(cssClass('handle'));
-		};
-		/*}}}*/
-		function insertDragbar(ord)/*{{{*/
-		{
-			var s = options.handleSize,
-				o = hhs,
-				h = s, w = s,
-				t = o, l = o;
+        return makeObj(flipCoords(x1, y1, x2, y2));
+      }
+      //}}}
+      function makeObj(a) //{{{
+      {
+        return {
+          x: a[0],
+          y: a[1],
+          x2: a[2],
+          y2: a[3],
+          w: a[2] - a[0],
+          h: a[3] - a[1]
+        };
+      }
+      //}}}
 
-			switch(ord)
-			{
-				case 'n': case 's': w = pct(100); break;
-				case 'e': case 'w': h = pct(100); break;
-			}
+      return {
+        flipCoords: flipCoords,
+        setPressed: setPressed,
+        setCurrent: setCurrent,
+        getOffset: getOffset,
+        moveOffset: moveOffset,
+        getCorner: getCorner,
+        getFixed: getFixed
+      };
+    }());
 
-			return dragDiv(ord,hdep++).width(w).height(h)
-				.css({ top: px(-t+1), left: px(-l+1)});
-		};
-		/*}}}*/
-		function createHandles(li)/*{{{*/
-		{
-			for(i in li) handle[li[i]] = insertHandle(li[i]);
-		};
-		/*}}}*/
-		function moveHandles(c)/*{{{*/
-		{
-			var midvert  = Math.round((c.h / 2) - hhs),
-				midhoriz = Math.round((c.w / 2) - hhs),
-				north = west = -hhs+1,
-				east = c.w - hhs,
-				south = c.h - hhs,
-				x, y;
+    //}}}
+    // Shade Module {{{
+    var Shade = (function() {
+      var enabled = false,
+          holder = $('<div />').css({
+            position: 'absolute',
+            zIndex: 240,
+            opacity: 0
+          }),
+          shades = {
+            top: createShade(),
+            left: createShade().height(boundy),
+            right: createShade().height(boundy),
+            bottom: createShade()
+          };
 
-			'e' in handle &&
-				handle.e.css({ top: px(midvert), left: px(east) }) &&
-				handle.w.css({ top: px(midvert) }) &&
-				handle.s.css({ top: px(south), left: px(midhoriz) }) &&
-				handle.n.css({ left: px(midhoriz) });
+      function resizeShades(w,h) {
+        shades.left.css({ height: px(h) });
+        shades.right.css({ height: px(h) });
+      }
+      function updateAuto()
+      {
+        return updateShade(Coords.getFixed());
+      }
+      function updateShade(c)
+      {
+        shades.top.css({
+          left: px(c.x),
+          width: px(c.w),
+          height: px(c.y)
+        });
+        shades.bottom.css({
+          top: px(c.y2),
+          left: px(c.x),
+          width: px(c.w),
+          height: px(boundy-c.y2)
+        });
+        shades.right.css({
+          left: px(c.x2),
+          width: px(boundx-c.x2)
+        });
+        shades.left.css({
+          width: px(c.x)
+        });
+      }
+      function createShade() {
+        return $('<div />').css({
+          position: 'absolute',
+          backgroundColor: options.shadeColor||options.bgColor
+        }).appendTo(holder);
+      }
+      function enableShade() {
+        if (!enabled) {
+          enabled = true;
+          holder.insertBefore($img);
+          updateAuto();
+          Selection.setBgOpacity(1,0,1);
+          $img2.hide();
 
-			'ne' in handle &&
-				handle.ne.css({ left: px(east) }) &&
-				handle.se.css({ top: px(south), left: px(east) }) &&
-				handle.sw.css({ top: px(south) });
+          setBgColor(options.shadeColor||options.bgColor,1);
+          if (Selection.isAwake())
+          {
+            setOpacity(options.bgOpacity,1);
+          }
+            else setOpacity(1,1);
+        }
+      }
+      function setBgColor(color,now) {
+        colorChangeMacro(getShades(),color,now);
+      }
+      function disableShade() {
+        if (enabled) {
+          holder.remove();
+          $img2.show();
+          enabled = false;
+          if (Selection.isAwake()) {
+            Selection.setBgOpacity(options.bgOpacity,1,1);
+          } else {
+            Selection.setBgOpacity(1,1,1);
+            Selection.disableHandles();
+          }
+          colorChangeMacro($div,0,1);
+        }
+      }
+      function setOpacity(opacity,now) {
+        if (enabled) {
+          if (options.bgFade && !now) {
+            holder.animate({
+              opacity: 1-opacity
+            },{
+              queue: false,
+              duration: options.fadeTime
+            });
+          }
+          else holder.css({opacity:1-opacity});
+        }
+      }
+      function refreshAll() {
+        options.shade ? enableShade() : disableShade();
+        if (Selection.isAwake()) setOpacity(options.bgOpacity);
+      }
+      function getShades() {
+        return holder.children();
+      }
 
-			'b' in handle &&
-				handle.b.css({ top: px(south) }) &&
-				handle.r.css({ left: px(east) });
-		};
-		/*}}}*/
-		function moveto(x,y)/*{{{*/
-		{
-			$img2.css({ top: px(-y), left: px(-x) });
-			$sel.css({ top: px(y), left: px(x) });
-		};
-		/*}}}*/
-		function resize(w,h)/*{{{*/
-		{
-			$sel.width(w).height(h);
-		};
-		/*}}}*/
-		function refresh()/*{{{*/
-		{
-			var c = Coords.getFixed();
+      return {
+        update: updateAuto,
+        updateRaw: updateShade,
+        getShades: getShades,
+        setBgColor: setBgColor,
+        enable: enableShade,
+        disable: disableShade,
+        resize: resizeShades,
+        refresh: refreshAll,
+        opacity: setOpacity
+      };
+    }());
+    // }}}
+    // Selection Module {{{
+    var Selection = (function () {
+      var awake,
+          hdep = 370,
+          borders = {},
+          handle = {},
+          dragbar = {},
+          seehandles = false;
 
-			Coords.setPressed([c.x,c.y]);
-			Coords.setCurrent([c.x2,c.y2]);
+      // Private Methods
+      function insertBorder(type) //{{{
+      {
+        var jq = $('<div />').css({
+          position: 'absolute',
+          opacity: options.borderOpacity
+        }).addClass(cssClass(type));
+        $img_holder.append(jq);
+        return jq;
+      }
+      //}}}
+      function dragDiv(ord, zi) //{{{
+      {
+        var jq = $('<div />').mousedown(createDragger(ord)).css({
+          cursor: ord + '-resize',
+          position: 'absolute',
+          zIndex: zi
+        }).addClass('ord-'+ord);
 
-			updateVisible();
-		};
-		/*}}}*/
+        if (Touch.support) {
+          jq.bind('touchstart.jcrop', Touch.createDragger(ord));
+        }
 
-		// Internal Methods
-		function updateVisible()/*{{{*/
-			{ if (awake) return update(); };
-		/*}}}*/
-		function update()/*{{{*/
-		{
-			var c = Coords.getFixed();
+        $hdl_holder.append(jq);
+        return jq;
+      }
+      //}}}
+      function insertHandle(ord) //{{{
+      {
+        var hs = options.handleSize;
+        return dragDiv(ord, hdep++).css({
+          opacity: options.handleOpacity
+        }).width(hs).height(hs).addClass(cssClass('handle'));
+      }
+      //}}}
+      function insertDragbar(ord) //{{{
+      {
+        return dragDiv(ord, hdep++).addClass('jcrop-dragbar');
+      }
+      //}}}
+      function createDragbars(li) //{{{
+      {
+        var i;
+        for (i = 0; i < li.length; i++) {
+          dragbar[li[i]] = insertDragbar(li[i]);
+        }
+      }
+      //}}}
+      function createBorders(li) //{{{
+      {
+        var cl,i;
+        for (i = 0; i < li.length; i++) {
+          switch(li[i]){
+            case'n': cl='hline'; break;
+            case's': cl='hline bottom'; break;
+            case'e': cl='vline right'; break;
+            case'w': cl='vline'; break;
+          }
+          borders[li[i]] = insertBorder(cl);
+        }
+      }
+      //}}}
+      function createHandles(li) //{{{
+      {
+        var i;
+        for (i = 0; i < li.length; i++) {
+          handle[li[i]] = insertHandle(li[i]);
+        }
+      }
+      //}}}
+      function moveto(x, y) //{{{
+      {
+        if (!options.shade) {
+          $img2.css({
+            top: px(-y),
+            left: px(-x)
+          });
+        }
+        $sel.css({
+          top: px(y),
+          left: px(x)
+        });
+      }
+      //}}}
+      function resize(w, h) //{{{
+      {
+        $sel.width(w).height(h);
+      }
+      //}}}
+      function refresh() //{{{
+      {
+        var c = Coords.getFixed();
 
-			resize(c.w,c.h);
-			moveto(c.x,c.y);
+        Coords.setPressed([c.x, c.y]);
+        Coords.setCurrent([c.x2, c.y2]);
 
-			options.drawBorders &&
-				borders['right'].css({ left: px(c.w-1) }) &&
-					borders['bottom'].css({ top: px(c.h-1) });
+        updateVisible();
+      }
+      //}}}
 
-			seehandles && moveHandles(c);
-			awake || show();
+      // Internal Methods
+      function updateVisible(select) //{{{
+      {
+        if (awake) {
+          return update(select);
+        }
+      }
+      //}}}
+      function update(select) //{{{
+      {
+        var c = Coords.getFixed();
 
-			options.onChange(unscale(c));
-		};
-		/*}}}*/
-		function show()/*{{{*/
-		{
-			$sel.show();
-			$img.css('opacity',options.bgOpacity);
-			awake = true;
-		};
-		/*}}}*/
-		function release()/*{{{*/
-		{
-			disableHandles();
-			$sel.hide();
-			$img.css('opacity',1);
-			awake = false;
-		};
-		/*}}}*/
-		function showHandles()//{{{
-		{
-			if (seehandles)
-			{
-				moveHandles(Coords.getFixed());
-				$hdl_holder.show();
-			}
-		};
-		//}}}
-		function enableHandles()/*{{{*/
-		{ 
-			seehandles = true;
-			if (options.allowResize)
-			{
-				moveHandles(Coords.getFixed());
-				$hdl_holder.show();
-				return true;
-			}
-		};
-		/*}}}*/
-		function disableHandles()/*{{{*/
-		{
-			seehandles = false;
-			$hdl_holder.hide();
-		};
-		/*}}}*/
-		function animMode(v)/*{{{*/
-		{
-			(animating = v) ? disableHandles(): enableHandles();
-		};
-		/*}}}*/
-		function done()/*{{{*/
-		{
-			animMode(false);
-			refresh();
-		};
-		/*}}}*/
+        resize(c.w, c.h);
+        moveto(c.x, c.y);
+        if (options.shade) Shade.updateRaw(c);
 
-		var $track = newTracker().mousedown(createDragger('move'))
-				.css({ cursor: 'move', position: 'absolute', zIndex: 360 })
+        awake || show();
 
-		$img_holder.append($track);
-		disableHandles();
+        if (select) {
+          options.onSelect.call(api, unscale(c));
+        } else {
+          options.onChange.call(api, unscale(c));
+        }
+      }
+      //}}}
+      function setBgOpacity(opacity,force,now) //{{{
+      {
+        if (!awake && !force) return;
+        if (options.bgFade && !now) {
+          $img.animate({
+            opacity: opacity
+          },{
+            queue: false,
+            duration: options.fadeTime
+          });
+        } else {
+          $img.css('opacity', opacity);
+        }
+      }
+      //}}}
+      function show() //{{{
+      {
+        $sel.show();
 
-		return {
-			updateVisible: updateVisible,
-			update: update,
-			release: release,
-			refresh: refresh,
-			setCursor: function (cursor) { $track.css('cursor',cursor); },
-			enableHandles: enableHandles,
-			enableOnly: function() { seehandles = true; },
-			showHandles: showHandles,
-			disableHandles: disableHandles,
-			animMode: animMode,
-			done: done
-		};
-	}();
-	/*}}}*/
-	var Tracker = function()/*{{{*/
-	{
-		var onMove		= function() { },
-			onDone		= function() { },
-			trackDoc	= options.trackDocument;
+        if (options.shade) Shade.opacity(bgopacity);
+          else setBgOpacity(bgopacity,true);
 
-		if (!trackDoc)
-		{
-			$trk
-				.mousemove(trackMove)
-				.mouseup(trackUp)
-				.mouseout(trackUp)
-			;
-		}
+        awake = true;
+      }
+      //}}}
+      function release() //{{{
+      {
+        disableHandles();
+        $sel.hide();
 
-		function toFront()/*{{{*/
-		{
-			$trk.css({zIndex:450});
-			if (trackDoc)
-			{
-				$(document)
-					.mousemove(trackMove)
-					.mouseup(trackUp)
-				;
-			}
-		}
-		/*}}}*/
-		function toBack()/*{{{*/
-		{
-			$trk.css({zIndex:290});
-			if (trackDoc)
-			{
-				$(document)
-					.unbind('mousemove',trackMove)
-					.unbind('mouseup',trackUp)
-				;
-			}
-		}
-		/*}}}*/
-		function trackMove(e)/*{{{*/
-		{
-			onMove(mouseAbs(e));
-		};
-		/*}}}*/
-		function trackUp(e)/*{{{*/
-		{
-			e.preventDefault();
-			e.stopPropagation();
+        if (options.shade) Shade.opacity(1);
+          else setBgOpacity(1);
 
-			if (btndown)
-			{
-				btndown = false;
+        awake = false;
+        options.onRelease.call(api);
+      }
+      //}}}
+      function showHandles() //{{{
+      {
+        if (seehandles) {
+          $hdl_holder.show();
+        }
+      }
+      //}}}
+      function enableHandles() //{{{
+      {
+        seehandles = true;
+        if (options.allowResize) {
+          $hdl_holder.show();
+          return true;
+        }
+      }
+      //}}}
+      function disableHandles() //{{{
+      {
+        seehandles = false;
+        $hdl_holder.hide();
+      } 
+      //}}}
+      function animMode(v) //{{{
+      {
+        if (animating === v) {
+          disableHandles();
+        } else {
+          enableHandles();
+        }
+      } 
+      //}}}
+      function done() //{{{
+      {
+        animMode(false);
+        refresh();
+      } 
+      //}}}
+      // Insert draggable elements {{{
+      // Insert border divs for outline
 
-				onDone(mouseAbs(e));
-				options.onSelect(unscale(Coords.getFixed()));
-				toBack();
-				onMove = function() { };
-				onDone = function() { };
-			}
+      if (options.dragEdges && $.isArray(options.createDragbars))
+        createDragbars(options.createDragbars);
 
-			return false;
-		};
-		/*}}}*/
+      if ($.isArray(options.createHandles))
+        createHandles(options.createHandles);
 
-		function activateHandlers(move,done)/* {{{ */
-		{
-			btndown = true;
-			onMove = move;
-			onDone = done;
-			toFront();
-			return false;
-		};
-		/* }}} */
+      if (options.drawBorders && $.isArray(options.createBorders))
+        createBorders(options.createBorders);
 
-		function setCursor(t) { $trk.css('cursor',t); };
+      //}}}
 
-		$img.before($trk);
-		return {
-			activateHandlers: activateHandlers,
-			setCursor: setCursor
-		};
-	}();
-	/*}}}*/
-	var KeyManager = function()/*{{{*/
-	{
-		var $keymgr = $('<input type="radio" />')
-				.css({ position: 'absolute', left: '-30px' })
-				.keypress(parseKey)
-				.blur(onBlur),
+      // This is a hack for iOS5 to support drag/move touch functionality
+      $(document).bind('touchstart.jcrop-ios',function(e) {
+        if ($(e.currentTarget).hasClass('jcrop-tracker')) e.stopPropagation();
+      });
 
-			$keywrap = $('<div />')
-				.css({
-					position: 'absolute',
-					overflow: 'hidden'
-				})
-				.append($keymgr)
-		;
+      var $track = newTracker().mousedown(createDragger('move')).css({
+        cursor: 'move',
+        position: 'absolute',
+        zIndex: 360
+      });
 
-		function watchKeys()/*{{{*/
-		{
-			if (options.keySupport)
-			{
-				$keymgr.show();
-				$keymgr.focus();
-			}
-		};
-		/*}}}*/
-		function onBlur(e)/*{{{*/
-		{
-			$keymgr.hide();
-		};
-		/*}}}*/
-		function doNudge(e,x,y)/*{{{*/
-		{
-			if (options.allowMove) {
-				Coords.moveOffset([x,y]);
-				Selection.updateVisible();
-			};
-			e.preventDefault();
-			e.stopPropagation();
-		};
-		/*}}}*/
-		function parseKey(e)/*{{{*/
-		{
-			if (e.ctrlKey) return true;
-			shift_down = e.shiftKey ? true : false;
-			var nudge = shift_down ? 10 : 1;
-			switch(e.keyCode)
-			{
-				case 37: doNudge(e,-nudge,0); break;
-				case 39: doNudge(e,nudge,0); break;
-				case 38: doNudge(e,0,-nudge); break;
-				case 40: doNudge(e,0,nudge); break;
+      if (Touch.support) {
+        $track.bind('touchstart.jcrop', Touch.createDragger('move'));
+      }
 
-				case 27: Selection.release(); break;
+      $img_holder.append($track);
+      disableHandles();
 
-				case 9: return true;
-			}
+      return {
+        updateVisible: updateVisible,
+        update: update,
+        release: release,
+        refresh: refresh,
+        isAwake: function () {
+          return awake;
+        },
+        setCursor: function (cursor) {
+          $track.css('cursor', cursor);
+        },
+        enableHandles: enableHandles,
+        enableOnly: function () {
+          seehandles = true;
+        },
+        showHandles: showHandles,
+        disableHandles: disableHandles,
+        animMode: animMode,
+        setBgOpacity: setBgOpacity,
+        done: done
+      };
+    }());
+    
+    //}}}
+    // Tracker Module {{{
+    var Tracker = (function () {
+      var onMove = function () {},
+          onDone = function () {},
+          trackDoc = options.trackDocument;
 
-			return nothing(e);
-		};
-		/*}}}*/
-		
-		if (options.keySupport) $keywrap.insertBefore($img);
-		return {
-			watchKeys: watchKeys
-		};
-	}();
-	/*}}}*/
+      function toFront() //{{{
+      {
+        $trk.css({
+          zIndex: 450
+        });
+        if (Touch.support) {
+          $(document)
+            .bind('touchmove.jcrop', trackTouchMove)
+            .bind('touchend.jcrop', trackTouchEnd);
+        }
+        if (trackDoc) {
+          $(document)
+            .bind('mousemove.jcrop',trackMove)
+            .bind('mouseup.jcrop',trackUp);
+        }
+      } 
+      //}}}
+      function toBack() //{{{
+      {
+        $trk.css({
+          zIndex: 290
+        });
+        $(document).unbind('.jcrop');
+      } 
+      //}}}
+      function trackMove(e) //{{{
+      {
+        onMove(mouseAbs(e));
+        return false;
+      } 
+      //}}}
+      function trackUp(e) //{{{
+      {
+        e.preventDefault();
+        e.stopPropagation();
 
-	// }}}
-	// Internal Methods {{{
+        if (btndown) {
+          btndown = false;
 
-	function px(n) { return '' + parseInt(n) + 'px'; };
-	function pct(n) { return '' + parseInt(n) + '%'; };
-	function cssClass(cl) { return options.baseClass + '-' + cl; };
-	function getPos(obj)/*{{{*/
-	{
-		// Updated in v0.9.4 to use built-in dimensions plugin
-		var pos = $(obj).offset();
-		return [ pos.left, pos.top ];
-	};
-	/*}}}*/
-	function mouseAbs(e)/*{{{*/
-	{
-		return [ (e.pageX - docOffset[0]), (e.pageY - docOffset[1]) ];
-	};
-	/*}}}*/
-	function myCursor(type)/*{{{*/
-	{
-		if (type != lastcurs)
-		{
-			Tracker.setCursor(type);
-			//Handles.xsetCursor(type);
-			lastcurs = type;
-		}
-	};
-	/*}}}*/
-	function startDragMode(mode,pos)/*{{{*/
-	{
-		docOffset = getPos($img);
-		Tracker.setCursor(mode=='move'?mode:mode+'-resize');
+          onDone(mouseAbs(e));
 
-		if (mode == 'move')
-			return Tracker.activateHandlers(createMover(pos), doneSelect);
+          if (Selection.isAwake()) {
+            options.onSelect.call(api, unscale(Coords.getFixed()));
+          }
 
-		var fc = Coords.getFixed();
-		var opp = oppLockCorner(mode);
-		var opc = Coords.getCorner(oppLockCorner(opp));
+          toBack();
+          onMove = function () {};
+          onDone = function () {};
+        }
 
-		Coords.setPressed(Coords.getCorner(opp));
-		Coords.setCurrent(opc);
+        return false;
+      }
+      //}}}
+      function activateHandlers(move, done) //{{{
+      {
+        btndown = true;
+        onMove = move;
+        onDone = done;
+        toFront();
+        return false;
+      }
+      //}}}
+      function trackTouchMove(e) //{{{
+      {
+        e.pageX = e.originalEvent.changedTouches[0].pageX;
+        e.pageY = e.originalEvent.changedTouches[0].pageY;
+        return trackMove(e);
+      }
+      //}}}
+      function trackTouchEnd(e) //{{{
+      {
+        e.pageX = e.originalEvent.changedTouches[0].pageX;
+        e.pageY = e.originalEvent.changedTouches[0].pageY;
+        return trackUp(e);
+      }
+      //}}}
+      function setCursor(t) //{{{
+      {
+        $trk.css('cursor', t);
+      }
+      //}}}
 
-		Tracker.activateHandlers(dragmodeHandler(mode,fc),doneSelect);
-	};
-	/*}}}*/
-	function dragmodeHandler(mode,f)/*{{{*/
-	{
-		return function(pos) {
-			if (!options.aspectRatio) switch(mode)
-			{
-				case 'e': pos[1] = f.y2; break;
-				case 'w': pos[1] = f.y2; break;
-				case 'n': pos[0] = f.x2; break;
-				case 's': pos[0] = f.x2; break;
-			}
-			else switch(mode)
-			{
-				case 'e': pos[1] = f.y+1; break;
-				case 'w': pos[1] = f.y+1; break;
-				case 'n': pos[0] = f.x+1; break;
-				case 's': pos[0] = f.x+1; break;
-			}
-			Coords.setCurrent(pos);
-			Selection.update();
-		};
-	};
-	/*}}}*/
-	function createMover(pos)/*{{{*/
-	{
-		var lloc = pos;
-		KeyManager.watchKeys();
+      if (!trackDoc) {
+        $trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);
+      }
 
-		return function(pos)
-		{
-			Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]);
-			lloc = pos;
-			
-			Selection.update();
-		};
-	};
-	/*}}}*/
-	function oppLockCorner(ord)/*{{{*/
-	{
-		switch(ord)
-		{
-			case 'n': return 'sw';
-			case 's': return 'nw';
-			case 'e': return 'nw';
-			case 'w': return 'ne';
-			case 'ne': return 'sw';
-			case 'nw': return 'se';
-			case 'se': return 'nw';
-			case 'sw': return 'ne';
-		};
-	};
-	/*}}}*/
-	function createDragger(ord)/*{{{*/
-	{
-		return function(e) {
-			if (options.disabled) return false;
-			if ((ord == 'move') && !options.allowMove) return false;
-			btndown = true;
-			startDragMode(ord,mouseAbs(e));
-			e.stopPropagation();
-			e.preventDefault();
-			return false;
-		};
-	};
-	/*}}}*/
-	function presize($obj,w,h)/*{{{*/
-	{
-		var nw = $obj.width(), nh = $obj.height();
-		if ((nw > w) && w > 0)
-		{
-			nw = w;
-			nh = (w/$obj.width()) * $obj.height();
-		}
-		if ((nh > h) && h > 0)
-		{
-			nh = h;
-			nw = (h/$obj.height()) * $obj.width();
-		}
-		xscale = $obj.width() / nw;
-		yscale = $obj.height() / nh;
-		$obj.width(nw).height(nh);
-	};
-	/*}}}*/
-	function unscale(c)/*{{{*/
-	{
-		return {
-			x: parseInt(c.x * xscale), y: parseInt(c.y * yscale), 
-			x2: parseInt(c.x2 * xscale), y2: parseInt(c.y2 * yscale), 
-			w: parseInt(c.w * xscale), h: parseInt(c.h * yscale)
-		};
-	};
-	/*}}}*/
-	function doneSelect(pos)/*{{{*/
-	{
-		var c = Coords.getFixed();
-		if (c.w > options.minSelect[0] && c.h > options.minSelect[1])
-		{
-			Selection.enableHandles();
-			Selection.done();
-		}
-		else
-		{
-			Selection.release();
-		}
-		Tracker.setCursor( options.allowSelect?'crosshair':'default' );
-	};
-	/*}}}*/
-	function newSelection(e)/*{{{*/
-	{
-		if (options.disabled) return false;
-		if (!options.allowSelect) return false;
-		btndown = true;
-		docOffset = getPos($img);
-		Selection.disableHandles();
-		myCursor('crosshair');
-		var pos = mouseAbs(e);
-		Coords.setPressed(pos);
-		Tracker.activateHandlers(selectDrag,doneSelect);
-		KeyManager.watchKeys();
-		Selection.update();
+      $img.before($trk);
+      return {
+        activateHandlers: activateHandlers,
+        setCursor: setCursor
+      };
+    }());
+    //}}}
+    // KeyManager Module {{{
+    var KeyManager = (function () {
+      var $keymgr = $('<input type="radio" />').css({
+        position: 'fixed',
+        left: '-120px',
+        width: '12px'
+      }),
+          $keywrap = $('<div />').css({
+          position: 'absolute',
+          overflow: 'hidden'
+        }).append($keymgr);
 
-		e.stopPropagation();
-		e.preventDefault();
-		return false;
-	};
-	/*}}}*/
-	function selectDrag(pos)/*{{{*/
-	{
-		Coords.setCurrent(pos);
-		Selection.update();
-	};
-	/*}}}*/
-	function newTracker()
-	{
-		var trk = $('<div></div>').addClass(cssClass('tracker'));
-		$.browser.msie && trk.css({ opacity: 0, backgroundColor: 'white' });
-		return trk;
-	};
+      function watchKeys() //{{{
+      {
+        if (options.keySupport) {
+          $keymgr.show();
+          $keymgr.focus();
+        }
+      }
+      //}}}
+      function onBlur(e) //{{{
+      {
+        $keymgr.hide();
+      }
+      //}}}
+      function doNudge(e, x, y) //{{{
+      {
+        if (options.allowMove) {
+          Coords.moveOffset([x, y]);
+          Selection.updateVisible(true);
+        }
+        e.preventDefault();
+        e.stopPropagation();
+      }
+      //}}}
+      function parseKey(e) //{{{
+      {
+        if (e.ctrlKey || e.metaKey) {
+          return true;
+        }
+        shift_down = e.shiftKey ? true : false;
+        var nudge = shift_down ? 10 : 1;
 
-	// }}}
-	// API methods {{{
-		
-	function animateTo(a)/*{{{*/
-	{
-		var x1 = a[0] / xscale,
-			y1 = a[1] / yscale,
-			x2 = a[2] / xscale,
-			y2 = a[3] / yscale;
+        switch (e.keyCode) {
+        case 37:
+          doNudge(e, -nudge, 0);
+          break;
+        case 39:
+          doNudge(e, nudge, 0);
+          break;
+        case 38:
+          doNudge(e, 0, -nudge);
+          break;
+        case 40:
+          doNudge(e, 0, nudge);
+          break;
+        case 27:
+          if (options.allowSelect) Selection.release();
+          break;
+        case 9:
+          return true;
+        }
 
-		if (animating) return;
+        return false;
+      }
+      //}}}
 
-		var animto = Coords.flipCoords(x1,y1,x2,y2);
-		var c = Coords.getFixed();
-		var animat = initcr = [ c.x, c.y, c.x2, c.y2 ];
-		var interv = options.animationDelay;
+      if (options.keySupport) {
+        $keymgr.keydown(parseKey).blur(onBlur);
+        if (ie6mode || !options.fixedSupport) {
+          $keymgr.css({
+            position: 'absolute',
+            left: '-20px'
+          });
+          $keywrap.append($keymgr).insertBefore($img);
+        } else {
+          $keymgr.insertBefore($img);
+        }
+      }
 
-		var x = animat[0];
-		var y = animat[1];
-		var x2 = animat[2];
-		var y2 = animat[3];
-		var ix1 = animto[0] - initcr[0];
-		var iy1 = animto[1] - initcr[1];
-		var ix2 = animto[2] - initcr[2];
-		var iy2 = animto[3] - initcr[3];
-		var pcent = 0;
-		var velocity = options.swingSpeed;
 
-		Selection.animMode(true);
+      return {
+        watchKeys: watchKeys
+      };
+    }());
+    //}}}
+    // }}}
+    // API methods {{{
+    function setClass(cname) //{{{
+    {
+      $div.removeClass().addClass(cssClass('holder')).addClass(cname);
+    }
+    //}}}
+    function animateTo(a, callback) //{{{
+    {
+      var x1 = a[0] / xscale,
+          y1 = a[1] / yscale,
+          x2 = a[2] / xscale,
+          y2 = a[3] / yscale;
 
-		var animator = function()
-		{
-			return function()
-			{
-				pcent += (100 - pcent) / velocity;
+      if (animating) {
+        return;
+      }
 
-				animat[0] = x + ((pcent / 100) * ix1);
-				animat[1] = y + ((pcent / 100) * iy1);
-				animat[2] = x2 + ((pcent / 100) * ix2);
-				animat[3] = y2 + ((pcent / 100) * iy2);
+      var animto = Coords.flipCoords(x1, y1, x2, y2),
+          c = Coords.getFixed(),
+          initcr = [c.x, c.y, c.x2, c.y2],
+          animat = initcr,
+          interv = options.animationDelay,
+          ix1 = animto[0] - initcr[0],
+          iy1 = animto[1] - initcr[1],
+          ix2 = animto[2] - initcr[2],
+          iy2 = animto[3] - initcr[3],
+          pcent = 0,
+          velocity = options.swingSpeed;
 
-				if (pcent < 100) animateStart();
-					else Selection.done();
+      x = animat[0];
+      y = animat[1];
+      x2 = animat[2];
+      y2 = animat[3];
 
-				if (pcent >= 99.8) pcent = 100;
+      Selection.animMode(true);
+      var anim_timer;
 
-				setSelectRaw(animat);
-			};
-		}();
+      function queueAnimator() {
+        window.setTimeout(animator, interv);
+      }
+      var animator = (function () {
+        return function () {
+          pcent += (100 - pcent) / velocity;
 
-		function animateStart()
-			{ window.setTimeout(animator,interv); };
+          animat[0] = x + ((pcent / 100) * ix1);
+          animat[1] = y + ((pcent / 100) * iy1);
+          animat[2] = x2 + ((pcent / 100) * ix2);
+          animat[3] = y2 + ((pcent / 100) * iy2);
 
-		animateStart();
-	};
-	/*}}}*/
-	function setSelect(rect)//{{{
-	{
-		setSelectRaw([rect[0]/xscale,rect[1]/yscale,rect[2]/xscale,rect[3]/yscale]);
-	};
-	//}}}
-	function setSelectRaw(l) /*{{{*/
-	{
-		Coords.setPressed([l[0],l[1]]);
-		Coords.setCurrent([l[2],l[3]]);
-		Selection.update();
-	};
-	/*}}}*/
-	function setOptions(opt)/*{{{*/
-	{
-		if (typeof(opt) != 'object') opt = { };
-		options = $.extend(options,opt);
+          if (pcent >= 99.8) {
+            pcent = 100;
+          }
+          if (pcent < 100) {
+            setSelectRaw(animat);
+            queueAnimator();
+          } else {
+            Selection.done();
+            if (typeof(callback) === 'function') {
+              callback.call(api);
+            }
+          }
+        };
+      }());
+      queueAnimator();
+    }
+    //}}}
+    function setSelect(rect) //{{{
+    {
+      setSelectRaw([rect[0] / xscale, rect[1] / yscale, rect[2] / xscale, rect[3] / yscale]);
+      options.onSelect.call(api, unscale(Coords.getFixed()));
+      Selection.enableHandles();
+    }
+    //}}}
+    function setSelectRaw(l) //{{{
+    {
+      Coords.setPressed([l[0], l[1]]);
+      Coords.setCurrent([l[2], l[3]]);
+      Selection.update();
+    }
+    //}}}
+    function tellSelect() //{{{
+    {
+      return unscale(Coords.getFixed());
+    }
+    //}}}
+    function tellScaled() //{{{
+    {
+      return Coords.getFixed();
+    }
+    //}}}
+    function setOptionsNew(opt) //{{{
+    {
+      setOptions(opt);
+      interfaceUpdate();
+    }
+    //}}}
+    function disableCrop() //{{{
+    {
+      options.disabled = true;
+      Selection.disableHandles();
+      Selection.setCursor('default');
+      Tracker.setCursor('default');
+    }
+    //}}}
+    function enableCrop() //{{{
+    {
+      options.disabled = false;
+      interfaceUpdate();
+    }
+    //}}}
+    function cancelCrop() //{{{
+    {
+      Selection.done();
+      Tracker.activateHandlers(null, null);
+    }
+    //}}}
+    function destroy() //{{{
+    {
+      $div.remove();
+      $origimg.show();
+      $(obj).removeData('Jcrop');
+    }
+    //}}}
+    function setImage(src, callback) //{{{
+    {
+      Selection.release();
+      disableCrop();
+      var img = new Image();
+      img.onload = function () {
+        var iw = img.width;
+        var ih = img.height;
+        var bw = options.boxWidth;
+        var bh = options.boxHeight;
+        $img.width(iw).height(ih);
+        $img.attr('src', src);
+        $img2.attr('src', src);
+        presize($img, bw, bh);
+        boundx = $img.width();
+        boundy = $img.height();
+        $img2.width(boundx).height(boundy);
+        $trk.width(boundx + (bound * 2)).height(boundy + (bound * 2));
+        $div.width(boundx).height(boundy);
+        Shade.resize(boundx,boundy);
+        enableCrop();
 
-		if (typeof(options.onChange)!=='function')
-			options.onChange = function() { };
+        if (typeof(callback) === 'function') {
+          callback.call(api);
+        }
+      };
+      img.src = src;
+    }
+    //}}}
+    function colorChangeMacro($obj,color,now) {
+      var mycolor = color || options.bgColor;
+      if (options.bgFade && supportsColorFade() && options.fadeTime && !now) {
+        $obj.animate({
+          backgroundColor: mycolor
+        }, {
+          queue: false,
+          duration: options.fadeTime
+        });
+      } else {
+        $obj.css('backgroundColor', mycolor);
+      }
+    }
+    function interfaceUpdate(alt) //{{{
+    // This method tweaks the interface based on options object.
+    // Called when options are changed and at end of initialization.
+    {
+      if (options.allowResize) {
+        if (alt) {
+          Selection.enableOnly();
+        } else {
+          Selection.enableHandles();
+        }
+      } else {
+        Selection.disableHandles();
+      }
 
-		if (typeof(options.onSelect)!=='function')
-			options.onSelect = function() { };
+      Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
+      Selection.setCursor(options.allowMove ? 'move' : 'default');
 
-	};
-	/*}}}*/
-	function tellSelect()/*{{{*/
-	{
-		return unscale(Coords.getFixed());
-	};
-	/*}}}*/
-	function tellScaled()/*{{{*/
-	{
-		return Coords.getFixed();
-	};
-	/*}}}*/
-	function setOptionsNew(opt)/*{{{*/
-	{
-		setOptions(opt);
-		interfaceUpdate();
-	};
-	/*}}}*/
-	function disableCrop()//{{{
-	{
-		options.disabled = true;
-		Selection.disableHandles();
-		Selection.setCursor('default');
-		Tracker.setCursor('default');
-	};
-	//}}}
-	function enableCrop()//{{{
-	{
-		options.disabled = false;
-		interfaceUpdate();
-	};
-	//}}}
-	function cancelCrop()//{{{
-	{
-		Selection.done();
-		Tracker.activateHandlers(null,null);
-	};
-	//}}}
-	function destroy()//{{{
-	{
-		$div.remove();
-		$origimg.show();
-	};
-	//}}}
+      if (options.hasOwnProperty('trueSize')) {
+        xscale = options.trueSize[0] / boundx;
+        yscale = options.trueSize[1] / boundy;
+      }
 
-	function interfaceUpdate(alt)//{{{
-	// This method tweaks the interface based on options object.
-	// Called when options are changed and at end of initialization.
-	{
-		options.allowResize ?
-			alt?Selection.enableOnly():Selection.enableHandles():
-			Selection.disableHandles();
+      if (options.hasOwnProperty('setSelect')) {
+        setSelect(options.setSelect);
+        Selection.done();
+        delete(options.setSelect);
+      }
 
-		Tracker.setCursor( options.allowSelect? 'crosshair': 'default' );
-		Selection.setCursor( options.allowMove? 'move': 'default' );
+      Shade.refresh();
 
-		$div.css('backgroundColor',options.bgColor);
+      if (options.bgColor != bgcolor) {
+        colorChangeMacro(
+          options.shade? Shade.getShades(): $div,
+          options.shade?
+            (options.shadeColor || options.bgColor):
+            options.bgColor
+        );
+        bgcolor = options.bgColor;
+      }
 
-		if ('setSelect' in options) {
-			setSelect(opt.setSelect);
-			Selection.done();
-			delete(options.setSelect);
-		}
+      if (bgopacity != options.bgOpacity) {
+        bgopacity = options.bgOpacity;
+        if (options.shade) Shade.refresh();
+          else Selection.setBgOpacity(bgopacity);
+      }
 
-		if ('trueSize' in options) {
-			xscale = options.trueSize[0] / boundx;
-			yscale = options.trueSize[1] / boundy;
-		}
+      xlimit = options.maxSize[0] || 0;
+      ylimit = options.maxSize[1] || 0;
+      xmin = options.minSize[0] || 0;
+      ymin = options.minSize[1] || 0;
 
-		xlimit = options.maxSize[0] || 0;
-		ylimit = options.maxSize[1] || 0;
-		xmin = options.minSize[0] || 0;
-		ymin = options.minSize[1] || 0;
+      if (options.hasOwnProperty('outerImage')) {
+        $img.attr('src', options.outerImage);
+        delete(options.outerImage);
+      }
 
-		if ('outerImage' in options)
-		{
-			$img.attr('src',options.outerImage);
-			delete(options.outerImage);
-		}
+      Selection.refresh();
+    }
+    //}}}
+    //}}}
 
-		Selection.refresh();
-	};
-	//}}}
+    if (Touch.support) $trk.bind('touchstart.jcrop', Touch.newSelection);
 
-	// }}}
+    $hdl_holder.hide();
+    interfaceUpdate(true);
 
-	$hdl_holder.hide();
-	interfaceUpdate(true);
-	
-	var api = {
-		animateTo: animateTo,
-		setSelect: setSelect,
-		setOptions: setOptionsNew,
-		tellSelect: tellSelect,
-		tellScaled: tellScaled,
+    var api = {
+      setImage: setImage,
+      animateTo: animateTo,
+      setSelect: setSelect,
+      setOptions: setOptionsNew,
+      tellSelect: tellSelect,
+      tellScaled: tellScaled,
+      setClass: setClass,
 
-		disable: disableCrop,
-		enable: enableCrop,
-		cancel: cancelCrop,
+      disable: disableCrop,
+      enable: enableCrop,
+      cancel: cancelCrop,
+      release: Selection.release,
+      destroy: destroy,
 
-		focus: KeyManager.watchKeys,
+      focus: KeyManager.watchKeys,
 
-		getBounds: function() { return [ boundx * xscale, boundy * yscale ]; },
-		getWidgetSize: function() { return [ boundx, boundy ]; },
+      getBounds: function () {
+        return [boundx * xscale, boundy * yscale];
+      },
+      getWidgetSize: function () {
+        return [boundx, boundy];
+      },
+      getScaleFactor: function () {
+        return [xscale, yscale];
+      },
+      getOptions: function() {
+        // careful: internal values are returned
+        return options;
+      },
 
-		release: Selection.release,
-		destroy: destroy
+      ui: {
+        holder: $div,
+        selection: $sel
+      }
+    };
 
-	};
+    if ($.browser.msie)
+      $div.bind('selectstart', function () { return false; });
 
-	$origimg.data('Jcrop',api);
-	return api;
-};
+    $origimg.data('Jcrop', api);
+    return api;
+  };
+  $.fn.Jcrop = function (options, callback) //{{{
+  {
+    var api;
+    // Iterate over each object, attach Jcrop
+    this.each(function () {
+      // If we've already attached to this object
+      if ($(this).data('Jcrop')) {
+        // The API can be requested this way (undocumented)
+        if (options === 'api') return $(this).data('Jcrop');
+        // Otherwise, we just reset the options...
+        else $(this).data('Jcrop').setOptions(options);
+      }
+      // If we haven't been attached, preload and attach
+      else {
+        if (this.tagName == 'IMG')
+          $.Jcrop.Loader(this,function(){
+            $(this).css({display:'block',visibility:'hidden'});
+            api = $.Jcrop(this, options);
+            if ($.isFunction(callback)) callback.call(api);
+          });
+        else {
+          $(this).css({display:'block',visibility:'hidden'});
+          api = $.Jcrop(this, options);
+          if ($.isFunction(callback)) callback.call(api);
+        }
+      }
+    });
 
-$.fn.Jcrop = function(options)/*{{{*/
-{
-	function attachWhenDone(from)/*{{{*/
-	{
-		var loadsrc = options.useImg || from.src;
-		var img = new Image();
-		img.onload = function() { $.Jcrop(from,options); };
-		img.src = loadsrc;
-	};
-	/*}}}*/
-	if (typeof(options) !== 'object') options = { };
+    // Return "this" so the object is chainable (jQuery-style)
+    return this;
+  };
+  //}}}
+  // $.Jcrop.Loader - basic image loader {{{
 
-	// Iterate over each object, attach Jcrop
-	this.each(function()
-	{
-		// If we've already attached to this object
-		if ($(this).data('Jcrop'))
-		{
-			// The API can be requested this way (undocumented)
-			if (options == 'api') return $(this).data('Jcrop');
-			// Otherwise, we just reset the options...
-			else $(this).data('Jcrop').setOptions(options);
-		}
-		// If we haven't been attached, preload and attach
-		else attachWhenDone(this);
-	});
+  $.Jcrop.Loader = function(imgobj,success,error){
+    var $img = $(imgobj), img = $img[0];
 
-	// Return "this" so we're chainable a la jQuery plugin-style!
-	return this;
-};
-/*}}}*/
+    function completeCheck(){
+      if (img.complete) {
+        $img.unbind('.jcloader');
+        if ($.isFunction(success)) success.call(img);
+      }
+      else window.setTimeout(completeCheck,50);
+    }
 
-})(jQuery);
+    $img
+      .bind('load.jcloader',completeCheck)
+      .bind('error.jcloader',function(e){
+        $img.unbind('.jcloader');
+        if ($.isFunction(error)) error.call(img);
+      });
+
+    if (img.complete && $.isFunction(success)){
+      $img.unbind('.jcloader');
+      success.call(img);
+    }
+  };
+
+  //}}}
+  // Global Defaults {{{
+  $.Jcrop.defaults = {
+
+    // Basic Settings
+    allowSelect: true,
+    allowMove: true,
+    allowResize: true,
+
+    trackDocument: true,
+
+    // Styling Options
+    baseClass: 'jcrop',
+    addClass: null,
+    bgColor: 'black',
+    bgOpacity: 0.6,
+    bgFade: false,
+    borderOpacity: 0.4,
+    handleOpacity: 0.5,
+    handleSize: 7,
+
+    aspectRatio: 0,
+    keySupport: true,
+    createHandles: ['n','s','e','w','nw','ne','se','sw'],
+    createDragbars: ['n','s','e','w'],
+    createBorders: ['n','s','e','w'],
+    drawBorders: true,
+    dragEdges: true,
+    fixedSupport: true,
+    touchSupport: null,
+
+    shade: null,
+
+    boxWidth: 0,
+    boxHeight: 0,
+    boundary: 2,
+    fadeTime: 400,
+    animationDelay: 20,
+    swingSpeed: 3,
+
+    minSelect: [0, 0],
+    maxSize: [0, 0],
+    minSize: [0, 0],
+
+    // Callbacks / Event Handlers
+    onChange: function () {},
+    onSelect: function () {},
+    onDblClick: function () {},
+    onRelease: function () {}
+  };
+
+  // }}}
+}(jQuery));
