/**
 * jquery.Jcrop.js v0.9.9
 * 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
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * 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
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * 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($) {

		$.Jcrop = function(obj, opt) {
			var options = $.extend({}, $.Jcrop.defaults), docOffset, lastcurs, ie6mode = false;

			// Internal Methods {{{
			function px(n) {
				return parseInt(n, 10) + '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);

				$.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');

				if (mode === 'move') {
					return Tracker.activateHandlers(createMover(pos), doneSelect);
				}

				var fc = Coords.getFixed();
				var opp = oppLockCorner(mode);
				var opc = Coords.getCorner(oppLockCorner(opp));

				Coords.setPressed(Coords.getCorner(opp));
				Coords.setCurrent(opc);

				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();

				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;
					}

					// 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);

					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, 10),
					y : parseInt(c.y * yscale, 10),
					x2 : parseInt(c.x2 * xscale, 10),
					y2 : parseInt(c.y2 * yscale, 10),
					w : parseInt(c.w * xscale, 10),
					h : parseInt(c.h * yscale, 10)
				};
			}

			//}}}
			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();

				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;
			}

			//}}}

			// }}}
			// 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
			};

			var $origimg = $(obj), img_mode = true;

			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 $img = $origimg.clone().removeAttr('id').css(img_css).show();

				$img.width($origimg.width());
				$img.height($origimg.height());
				$origimg.after($img).hide();

			} else {
				$img = $origimg.css(img_css).show();
				img_mode = false;
				if (options.shade === null) {
					options.shade = true;
				}
			}

			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);

			if (options.addClass) {
				$div.addClass(options.addClass);
			}

			var $img2 = $('<div />'), $img_holder = $('<div />').width('100%').height('100%').css({
				zIndex : 310,
				position : 'absolute',
				overflow : 'hidden'
			}), $hdl_holder = $('<div />').width('100%').height('100%').css('zIndex', 320), $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) {

				$img2 = $('<img />').attr('src', $img.attr('src')).css(img_css).width(boundx).height(boundy), $img_holder.append($img2);

			}

			if (ie6mode) {
				$sel.css({
					overflowY : '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 {{{
			var bgcolor = options.bgColor, bgopacity = options.bgOpacity, xlimit, ylimit, xmin, ymin, xscale, yscale, enabled = true, btndown, animating, shift_down;

			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;

						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;
						}
					}

					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;

					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];

						if (0 > x1 + ox) {
							ox -= ox + x1;
						}
						if (0 > y1 + oy) {
							oy -= oy + y1;
						}

						if (boundy < y2 + oy) {
							oy += boundy - (y2 + oy);
						}
						if (boundx < x2 + ox) {
							ox += boundx - (x2 + ox);
						}

						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 (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 (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;
							}
						}

						// 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;
							}
						}

						if (xx < 0) {
							x1 -= xx;
							xx = 0;
						} else if (xx > boundx) {
							x1 -= xx - boundx;
							xx = boundx;
						}

						if (yy < 0) {
							y1 -= yy;
							yy = 0;
						} else if (yy > boundy) {
							y1 -= yy - boundy;
							yy = boundy;
						}

						return makeObj(flipCoords(x1, y1, xx, yy));
					}

					//}}}
					function rebound(p)//{{{
					{
						if (p[0] < 0) {
							p[0] = 0;
						}
						if (p[1] < 0) {
							p[1] = 0;
						}

						if (p[0] > boundx) {
							p[0] = boundx;
						}
						if (p[1] > boundy) {
							p[1] = boundy;
						}

						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, ysize = y2 - y1, delta;

						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 (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);
						}

						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;
						}

						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]
						};
					}

					//}}}

					return {
						flipCoords : flipCoords,
						setPressed : setPressed,
						setCurrent : setCurrent,
						getOffset : getOffset,
						moveOffset : moveOffset,
						getCorner : getCorner,
						getFixed : getFixed
					};
				}());

			//}}}
			// 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()
					};

					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();

							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();
					}

					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;

					// 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);

						if (Touch.support) {
							jq.bind('touchstart.jcrop', Touch.createDragger(ord));
						}

						$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();

						Coords.setPressed([c.x, c.y]);
						Coords.setCurrent([c.x2, c.y2]);

						updateVisible();
					}

					//}}}

					// Internal Methods
					function updateVisible(select)//{{{
					{
						if (awake) {
							return update(select);
						}
					}

					//}}}
					function update(select)//{{{
					{
						var c = Coords.getFixed();

						resize(c.w, c.h);
						moveto(c.x, c.y);
						if (options.shade)
							Shade.updateRaw(c);

						awake || show();

						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();

						if (options.shade)
							Shade.opacity(bgopacity);
						else
							setBgOpacity(bgopacity, true);

						awake = true;
					}

					//}}}
					function release()//{{{
					{
						disableHandles();
						$sel.hide();

						if (options.shade)
							Shade.opacity(1);
						else
							setBgOpacity(1);

						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

					if (options.dragEdges && $.isArray(options.createDragbars))
						createDragbars(options.createDragbars);

					if ($.isArray(options.createHandles))
						createHandles(options.createHandles);

					if (options.drawBorders && $.isArray(options.createBorders))
						createBorders(options.createBorders);

					//}}}

					// 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();
					});

					var $track = newTracker().mousedown(createDragger('move')).css({
						cursor : 'move',
						position : 'absolute',
						zIndex : 360
					});

					if (Touch.support) {
						$track.bind('touchstart.jcrop', Touch.createDragger('move'));
					}

					$img_holder.append($track);
					disableHandles();

					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;

					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();

						if (btndown) {
							btndown = false;

							onDone(mouseAbs(e));

							if (Selection.isAwake()) {
								options.onSelect.call(api, unscale(Coords.getFixed()));
							}

							toBack();
							onMove = function() {
							};
							onDone = function() {
							};
						}

						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);
					}

					//}}}

					if (!trackDoc) {
						$trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);
					}

					$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);

					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;

						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;
						}

						return false;
					}

					//}}}

					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);
						}
					}

					return {
						watchKeys : watchKeys
					};
				}());
			//}}}
			// }}}
			// API methods {{{
			function setClass(cname)//{{{
			{
				$div.removeClass().addClass(cssClass('holder')).addClass(cname);
			}

			//}}}
			function animateTo(a, callback)//{{{
			{
				var x1 = parseInt(a[0], 10) / xscale, y1 = parseInt(a[1], 10) / yscale, x2 = parseInt(a[2], 10) / xscale, y2 = parseInt(a[3], 10) / yscale;

				if (animating) {
					return;
				}

				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;

				x = animat[0];
				y = animat[1];
				x2 = animat[2];
				y2 = animat[3];

				Selection.animMode(true);
				var anim_timer;

				function queueAnimator() {
					window.setTimeout(animator, interv);
				}

				var animator = ( function() {
						return function() {
							pcent += (100 - pcent) / velocity;

							animat[0] = x + ((pcent / 100) * ix1);
							animat[1] = y + ((pcent / 100) * iy1);
							animat[2] = x2 + ((pcent / 100) * ix2);
							animat[3] = y2 + ((pcent / 100) * iy2);

							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([parseInt(rect[0], 10) / xscale, parseInt(rect[1], 10) / yscale, parseInt(rect[2], 10) / xscale, parseInt(rect[3], 10) / 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 (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();
				}

				Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
				Selection.setCursor(options.allowMove ? 'move' : 'default');

				if (options.hasOwnProperty('trueSize')) {
					xscale = options.trueSize[0] / boundx;
					yscale = options.trueSize[1] / boundy;
				}

				if (options.hasOwnProperty('setSelect')) {
					setSelect(options.setSelect);
					Selection.done();
					delete (options.setSelect);
				}

				Shade.refresh();

				if (options.bgColor != bgcolor) {
					colorChangeMacro(options.shade ? Shade.getShades() : $div, options.shade ? (options.shadeColor || options.bgColor) : options.bgColor);
					bgcolor = options.bgColor;
				}

				if (bgopacity != options.bgOpacity) {
					bgopacity = options.bgOpacity;
					if (options.shade)
						Shade.refresh();
					else
						Selection.setBgOpacity(bgopacity);
				}

				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);
				}

				Selection.refresh();
			}

			//}}}
			//}}}

			if (Touch.support)
				$trk.bind('touchstart.jcrop', Touch.newSelection);

			$hdl_holder.hide();
			interfaceUpdate(true);

			var api = {
				setImage : setImage,
				animateTo : animateTo,
				setSelect : setSelect,
				setOptions : setOptionsNew,
				tellSelect : tellSelect,
				tellScaled : tellScaled,
				setClass : setClass,

				disable : disableCrop,
				enable : enableCrop,
				cancel : cancelCrop,
				release : Selection.release,
				destroy : destroy,

				focus : KeyManager.watchKeys,

				getBounds : function() {
					return [boundx * xscale, boundy * yscale];
				},
				getWidgetSize : function() {
					return [boundx, boundy];
				},
				getScaleFactor : function() {
					return [xscale, yscale];
				},

				ui : {
					holder : $div,
					selection : $sel
				}
			};

			if ($.browser.msie)
				$div.bind('selectstart', function() {
					return false;
				});

			$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);
					}
				}
			});

			// Return "this" so the object is chainable (jQuery-style)
			return this;
		};
		//}}}
		// $.Jcrop.Loader - basic image loader {{{

		$.Jcrop.Loader = function(imgobj, success, error) {
			var $img = $(imgobj), img = $img[0];

			function completeCheck() {
				if (img.complete) {
					$img.unbind('.jcloader');
					if ($.isFunction(success))
						success.call(img);
				} else
					window.setTimeout(completeCheck, 50);
			}


			$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));
