// -----------------------------------------------------------------------
// PRINT ELEMENT
// -----------------------------------------------------------------------
// eros@recoding.it
// jqprint 0.3
//
// - 19/06/2009 - some new implementations, added Opera support
// - 11/05/2009 - first sketch
//
// Printing plug-in for jQuery, evolution of jPrintArea: http://plugins.jquery.com/project/jPrintArea
// requires jQuery 1.3.x
//------------------------------------------------------------------------

(function($) {
    var opt;

    $.fn.jqprint = function (options) {
        opt = $.extend({}, $.fn.jqprint.defaults, options);

        var $element = (this instanceof jQuery) ? this : $(this);
        
        if (opt.operaSupport && $.browser.opera) 
        { 
            var tab = window.open("","jqPrint-preview");
            tab.document.open();

            var doc = tab.document;
        }
        else 
        {
            var $iframe = $("<iframe  />");
        
            if (!opt.debug) { $iframe.css({ position: "absolute", width: "0px", height: "0px", left: "-600px", top: "-600px" }); }

            $iframe.appendTo("body");
            var doc = $iframe[0].contentWindow.document;
        }
        
        if (opt.importCSS)
        {
            if ($("link[media=print]").length > 0) 
            {
                $("link[media=print]").each( function() {
                    doc.write("<link type='text/css' rel='stylesheet' href='" + $(this).attr("href") + "' media='print' />");
                });
            }
            else 
            {
                $("link").each( function() {
                    doc.write("<link type='text/css' rel='stylesheet' href='" + $(this).attr("href") + "' />");
                });
            }
        }
        
        if (opt.printContainer) { doc.write($element.outer()); }
        else { $element.each( function() { doc.write($(this).html()); }); }
        
        doc.close();
        
        (opt.operaSupport && $.browser.opera ? tab : $iframe[0].contentWindow).focus();
        setTimeout( function() { (opt.operaSupport && $.browser.opera ? tab : $iframe[0].contentWindow).print(); if (tab) { tab.close(); } }, 1000);
    }
    
    $.fn.jqprint.defaults = {
		debug: false,
		importCSS: true, 
		printContainer: true,
		operaSupport: true
	};

    // Thanks to 9__, found at http://users.livejournal.com/9__/380664.html
    jQuery.fn.outer = function() {
      return $($('<div></div>').html(this.clone())).html();
    } 
})(jQuery);

// -----------------------------------------------------------------------
// COUNTDOWN 2
// -----------------------------------------------------------------------
jQuery.fn.countDown = function(settings,to) {
	settings = jQuery.extend({
		startFontSize: '36px',
		endFontSize: '12px',
		duration: 1000,
		startNumber: 10,
		endNumber: 0,
		callBack: function() { }
	}, settings);
	return this.each(function() {
		
		//where do we start?
		if(!to && to != settings.endNumber) { to = settings.startNumber; }
		
		//set the countdown to the starting number
		$(this).text(to).css('fontSize',settings.startFontSize);
		
		//loopage
		$(this).animate({
			'fontSize': settings.endFontSize
		},settings.duration,'',function() {
			if(to > settings.endNumber + 1) {
				$(this).css('fontSize',settings.startFontSize).text(to - 1).countDown(settings,to - 1);
			}
			else
			{
				settings.callBack(this);
			}
		});
				
	});
};

// -----------------------------------------------------------------------
// VERTICAL / HORIZONTAL MENU
// -----------------------------------------------------------------------
//** Smooth Navigational Menu- By Dynamic Drive DHTML code library: http://www.dynamicdrive.com
//** Script Download/ instructions page: http://www.dynamicdrive.com/dynamicindex1/ddlevelsmenu/
//** Menu created: Nov 12, 2008

//** Dec 12th, 08" (v1.01): Fixed Shadow issue when multiple LIs within the same UL (level) contain sub menus: http://www.dynamicdrive.com/forums/showthread.php?t=39177&highlight=smooth

//** Feb 11th, 09" (v1.02): The currently active main menu item (LI A) now gets a CSS class of ".selected", including sub menu items.

//** May 1st, 09" (v1.3):
//** 1) Now supports vertical (side bar) menu mode- set "orientation" to 'v'
//** 2) In IE6, shadows are now always disabled

//** July 27th, 09" (v1.31): Fixed bug so shadows can be disabled if desired.


var ddsmoothmenu={

//Specify full URL to down and right arrow images (23 is padding-right added to top level LIs with drop downs):
arrowimages: {down:['downarrowclass', 'images/down.gif', 23], right:['rightarrowclass', 'images/right.gif']},

transition: {overtime:300, outtime:300}, //duration of slide in/ out animation, in milliseconds
shadow: {enable:false, offsetx:5, offsety:5},

///////Stop configuring beyond here///////////////////////////

detectwebkit: navigator.userAgent.toLowerCase().indexOf("applewebkit")!=-1, //detect WebKit browsers (Safari, Chrome etc)
detectie6: document.all && !window.XMLHttpRequest,

getajaxmenu:function($, setting){ //function to fetch external page containing the panel DIVs
	var $menucontainer=$('#'+setting.contentsource[0]) //reference empty div on page that will hold menu
	$menucontainer.html("Loading Menu...")
	$.ajax({
		url: setting.contentsource[1], //path to external menu file
		async: true,
		error:function(ajaxrequest){
			$menucontainer.html('Error fetching content. Server Response: '+ajaxrequest.responseText)
		},
		success:function(content){
			$menucontainer.html(content)
			ddsmoothmenu.buildmenu($, setting)
		}
	})
},


buildmenu:function($, setting){
	var smoothmenu=ddsmoothmenu
	var $mainmenu=$("#"+setting.mainmenuid+">ul") //reference main menu UL
	$mainmenu.parent().get(0).className=setting.classname || "ddsmoothmenu"
	var $headers=$mainmenu.find("ul").parent()
	$headers.hover(
		function(e){
			$(this).children('a:eq(0)').addClass('selected')
		},
		function(e){
			$(this).children('a:eq(0)').removeClass('selected')
		}
	)
	$headers.each(function(i){ //loop through each LI header
		var $curobj=$(this).css({zIndex: 100-i}) //reference current LI header
		var $subul=$(this).find('ul:eq(0)').css({display:'block'})
		this._dimensions={w:this.offsetWidth, h:this.offsetHeight, subulw:$subul.outerWidth(), subulh:$subul.outerHeight()}
		this.istopheader=$curobj.parents("ul").length==1? true : false //is top level header?
		$subul.css({top:this.istopheader && setting.orientation!='v'? this._dimensions.h+"px" : 0})
		$curobj.children("a:eq(0)").css(this.istopheader? {paddingRight: smoothmenu.arrowimages.down[2]} : {}).append( //add arrow images
			'<img src="'+ (this.istopheader && setting.orientation!='v'? smoothmenu.arrowimages.down[1] : smoothmenu.arrowimages.right[1])
			+'" class="' + (this.istopheader && setting.orientation!='v'? smoothmenu.arrowimages.down[0] : smoothmenu.arrowimages.right[0])
			+ '" style="border:0;" />'
		)
		if (smoothmenu.shadow.enable){
			this._shadowoffset={x:(this.istopheader?$subul.offset().left+smoothmenu.shadow.offsetx : this._dimensions.w), y:(this.istopheader? $subul.offset().top+smoothmenu.shadow.offsety : $curobj.position().top)} //store this shadow's offsets
			if (this.istopheader)
				$parentshadow=$(document.body)
			else{
				var $parentLi=$curobj.parents("li:eq(0)")
				$parentshadow=$parentLi.get(0).$shadow
			}
			this.$shadow=$('<div class="ddshadow'+(this.istopheader? ' toplevelshadow' : '')+'"></div>').prependTo($parentshadow).css({left:this._shadowoffset.x+'px', top:this._shadowoffset.y+'px'})  //insert shadow DIV and set it to parent node for the next shadow div
		}
		$curobj.hover(
			function(e){
				var $targetul=$(this).children("ul:eq(0)")
				this._offsets={left:$(this).offset().left, top:$(this).offset().top}
				var menuleft=this.istopheader && setting.orientation!='v'? 0 : this._dimensions.w
				menuleft=(this._offsets.left+menuleft+this._dimensions.subulw>$(window).width())? (this.istopheader && setting.orientation!='v'? -this._dimensions.subulw+this._dimensions.w : -this._dimensions.w) : menuleft //calculate this sub menu's offsets from its parent
				if ($targetul.queue().length<=1){ //if 1 or less queued animations
					$targetul.css({left:menuleft+"px", width:this._dimensions.subulw+'px'}).animate({height:'show',opacity:'show'}, ddsmoothmenu.transition.overtime)
					if (smoothmenu.shadow.enable){
						var shadowleft=this.istopheader? $targetul.offset().left+ddsmoothmenu.shadow.offsetx : menuleft
						var shadowtop=this.istopheader?$targetul.offset().top+smoothmenu.shadow.offsety : this._shadowoffset.y
						if (!this.istopheader && ddsmoothmenu.detectwebkit){ //in WebKit browsers, restore shadow's opacity to full
							this.$shadow.css({opacity:1})
						}
						this.$shadow.css({overflow:'', width:this._dimensions.subulw+'px', left:shadowleft+'px', top:shadowtop+'px'}).animate({height:this._dimensions.subulh+'px'}, ddsmoothmenu.transition.overtime)
					}
				}
			},
			function(e){
				var $targetul=$(this).children("ul:eq(0)")
				$targetul.animate({height:'hide', opacity:'hide'}, ddsmoothmenu.transition.outtime)
				if (smoothmenu.shadow.enable){
					if (ddsmoothmenu.detectwebkit){ //in WebKit browsers, set first child shadow's opacity to 0, as "overflow:hidden" doesn't work in them
						this.$shadow.children('div:eq(0)').css({opacity:0})
					}
					this.$shadow.css({overflow:'hidden'}).animate({height:0}, ddsmoothmenu.transition.outtime)
				}
			}
		) //end hover
	}) //end $headers.each()
	$mainmenu.find("ul").css({display:'none', visibility:'visible'})
},

init:function(setting){
	if (typeof setting.customtheme=="object" && setting.customtheme.length==2){ //override default menu colors (default/hover) with custom set?
		var mainmenuid='#'+setting.mainmenuid
		var mainselector=(setting.orientation=="v")? mainmenuid : mainmenuid+', '+mainmenuid
		document.write('<style type="text/css">\n'
			+mainselector+' ul li a {background:'+setting.customtheme[0]+';}\n'
			+mainmenuid+' ul li a:hover {background:'+setting.customtheme[1]+';}\n'
		+'</style>')
	}
	this.shadow.enable=(document.all && !window.XMLHttpRequest)? false : this.shadow.enable //in IE6, always disable shadow
	jQuery(document).ready(function($){ //ajax menu?
		if (typeof setting.contentsource=="object"){ //if external ajax menu
			ddsmoothmenu.getajaxmenu($, setting)
		}
		else{ //else if markup menu
			ddsmoothmenu.buildmenu($, setting)
		}
	})
}

}; //end ddsmoothmenu variable

// -----------------------------------------------------------------------
// TOOLTIP
// -----------------------------------------------------------------------
(function($) {
	// http://github.com/lukasbob/Tooltip-Toolbox
	//
	// **Possible parameters:**
	//
	// _Event handler:_
	//
	// str showEvent		Defines the event that activates the tooltip.
	//							Possible values: mouseover, focus, click, dblclick, change etc.
	//							Default: "mouseover"
	// str hideEvent		Defines the event that hides the tooltip.
	//							Possible values: mouseout, blur, click, dblclick, change etc.
	//							Default: "mouseout"
	//
	// _CSS ids and classes:_
	//
	// str ttClass			Class for the tooltip for overriding and additional styling.
	//							Default: "tt_tip"
	// str activeClass	Class for the trigger element while tooltip is displayed.
	//							Default: "tt_active"
	// str ttIdPrefix 	Prefix for the element ID that identifies the tooltip ID.
	//							Example: element with id="test" looks for tooltip container with id="tt_test"
	//							Default: "tt_"
	//
	// _Positioning:_
	//
	// str align:			Preferred horizontal alignment of the tooltip. 
	//							Values: "absCenter", "center", "right", "left", "flushRight", and "flushLeft".
	//							Default: "flushLeft".
	// str vAlign:			Preferred vertical alignment of the tooltip.
	//							Values: "absCenter", "center", "above" and "below".
	//							Default: "above"
	// int windowMargin	The tooltip's minimum margin from the window's edge.
	//							Default: 5
	// int distanceX		The tooltip's horizontal distance from the trigger element.
	//							Not used if align is flushLeft, flushRight or centered.
	//							Default: 0	
	// int distanceY		The tooltip's vertical distance from the trigger element.
	//							Not used for if vAlign is centered.
	//							Default: 2
	// int nudgeX			Nudge along x axis. Use negative int to nudge left; positive int to nudge right.
	//							Default: 0
	// int nudgeY			Nudge along y axis. Use negative int to nudge up; positive int to nudge down.
	//							Default: 0
	//
	// _Timing:_
	//
	// int timeOut		Time that tooltip is displayed after mouseout.
	//							Default: 1000
	// int delay			Delay before displaying tooltip.
	//							Default: 500
	// int fadeOut			Time it take for the tooltip to fade out.
	//							Default: 250
	// int fadeIn			Time it take for the tooltip to fade in.
	//							Default: 100
	//
	// _Styling:_
	//
	// obj css				Object with CSS rules, applied in addition to default styles.
	//							As with jQuery CSS, use JavaScript CSS syntax, or quote properties.
	//							Example: "css: {textAlign: 'left'}" or "css: {'text-align': 'left'}"
	//							Default: Empty.
	// bool zoom			Use a zoom effect to animate the tooltip from the dimensions 
	//							and point of origin of the target element.
	//							Special case: If target and tooltip are both images, the image will zoom as well
	//							Default: false
	
	$.fn.tt = function(options) {
		// build main options before element iteration
		var opts = $.extend({},$.fn.tt.defaults,options);
		return this.each(function() {
			var $this = $(this),
				$ttTooltip,
				$ttOrg;
			
			// Support for the meta plugin
			var o = $.meta ? $.extend({},opts, $this.data()) : opts;

			//Storage object for cached positioning values
			$this.cache = {valid: false};
			$this.isOn = false;
			//Support for tooltips on the title attribute
			//Either use the trigger element's title attr or the target element, if it exists.
			if ($this.attr('id').length === 0 || !($('#' + o.ttIdPrefix + $this.attr('id'))[0])) {
				o.useTitle = true;
				$this.ttTitle = $this.oldTitle = $this.attr('title');
				$this.attr('title', '');
				$ttTooltip = $('<div><p>' + $this.ttTitle + '</p></div>').hide();
			} else {
				$ttTooltip = $('#' + o.ttIdPrefix + $this.attr('id')).hide();
				var orgPos = $('<i id="org_' + $.data($this) + '"/>').insertAfter($ttTooltip).hide();
			}
			//Set initial styles: Define standard styles if no custom class is set.
			var css = o.ttClass !== 'tt_tip' ? {position: 'absolute'} : {
				position: 'absolute',
				font: '11px "lucida grande", tahoma, helvetica, arial, sans-serif',
				border: '1px solid #666',
				background: '#ffd',
				padding: '.5em',
				'-webkit-border-radius': '5px',
				'-webkit-box-shadow': '0 6px 15px rgba(0,0,0,.6)',
				'-moz-border-radius': '5px',
				'-moz-box-shadow': '0 6px 15px rgba(0,0,0,.6)'
			};
			//Extend with options css properties
			css = $.extend({},css,o.css);
			
			//Set initial styling and class names from options.
			$ttTooltip.addClass(o.ttClass).css(css);
			
			$this.bind(o.showEvent, delayShowTip);				
			
			//Make sure that we do not hide the tooltip when the mouse is over it.
			$ttTooltip.bind('mouseover', function(e) {
				clearTimeout($this.hideTimer);
				$ttTooltip.one(o.hideEvent, hideTip);
			});
			if (o.visibleOnScroll) {
				//On scroll, recalculate position so we don't go offsreen.
				$(window).bind('scroll', function () {
					//Don't do anything igf the tooltip iis not on!'
					if ($this.isOn) {
						$ttTooltip.css(getTooltipPosition());
					}
				});
			}
			//On resize, kill cached position data and recalculate.
			$(window).bind('resize', function(){
				$this.cache.valid = false;
				//Don't reposition if tooltip isn't on!
					if ($this.isOn) {
						$ttTooltip.css(getTooltipPosition());
					}					
			});

			//
			// private functions
			//
			
			//A wrapper for the showTip function in order to enable delaying it.
			function delayShowTip() {
				clearTimeout($this.delayTimer);
				clearTimeout($this.hideTimer);
				$this.delayTimer = setTimeout(showTip, o.delay);
				$this.one(o.hideEvent, hideTip);
			}
			
			//Hide the Tooltip and do some cleanup.
			function hideTip() {
				clearTimeout($this.delayTimer);
				clearTimeout($this.hideTimer);
				$this.hideTimer = setTimeout(function() {
					//TODO: Is there a better way to handle nested tooltips? With a global bool isNested?
					//Don't hide tooltips that contain nested tooltips - wait for child element's activeClass to go away.
					if ($ttTooltip.find('.' + o.activeClass)[0]) {					
						hideTip();
						return;
					}					
					$this.removeClass(o.activeClass);
					$ttTooltip.fadeOut(o.fadeOut, function(){
						$this.isOn = false;
						//Cleanup: Put that content back where you found it!
						if (orgPos){
							$ttTooltip.insertBefore(orgPos);						
						}
					});
				},
				o.timeOut);
			}
			
			function showTip() {
				//If we use the target element's title, build the content.
				if (o.useTitle) {
					if ($this.ttTitle.length === 0) return;
				}
				//Move the tooltip to body to avoid issues with position and overflow CSS settings on the page.
				$ttTooltip.appendTo('body');
				$this.addClass(o.activeClass);
				$this.isOn = true;
				
				//Get target dimensions and position of the tooltip
				var tipPosition = getTooltipPosition();
				
				//Zoom!
				if (o.zoom) {
					var ratio = ($this.cache.elmDim.h * $this.cache.elmDim.w) / ($this.cache.ttInnerDim.h * $this.cache.ttInnerDim.w);
					// Named CSS attributes to scale by this area ratio:
					var cssAttrs = {'fontSize': ''};	
					var startCSS = {
						opacity: 0,
						left: $this.cache.elmOffset.left,
						top: $this.cache.elmOffset.top,
						width: $this.cache.elmDim.w,
						height: $this.cache.elmDim.h
					};
					var endCSS = $.extend({}, tipPosition, {
						width: $this.cache.ttInnerDim.w + 1, 
						height: $this.cache.ttInnerDim.h + 1,
						opacity: 1
					});
					for (i in cssAttrs) {
						cssAttrs[i] = endCSS[i] = $ttTooltip.css(i);
						startCSS[i] = parseInt(cssAttrs[i].split('px')[0], 10) * ratio;
					};
					//Set initial dimensions and position to be equal to the target element's
					$ttTooltip.css(startCSS);
					//Temporarily unbind events
					$ttTooltip.unbind(o.hideEvent, hideTip);
					$this.unbind(o.showEvent, delayShowTip).unbind(o.hideEvent, hideTip);
					$ttTooltip.addClass(o.ttClass).animate(endCSS, o.fadeIn, function() {
						//Rebind events.
						$ttTooltip.bind(o.hideEvent, hideTip);
						//Bind the showEvent. The hideEvent is bound on show.
						$this.bind(o.showEvent, delayShowTip);
					});
				} else {
					$ttTooltip.addClass(o.ttClass).css(tipPosition).fadeIn(o.fadeIn);
				}
			}
			function updateCache() {
				if ($this.cache.valid) return;
				$this.cache = {
					elmOffset: $this.offset(),
					elmDim: {
						w: $this.outerWidth(),
						h: $this.outerHeight()
					},
					ttDim: {
						w: $ttTooltip.outerWidth(),
						h: $ttTooltip.outerHeight()
					},
					ttInnerDim: {
						w: $ttTooltip.width(),
						h: $ttTooltip.height()
					},
					vp: {
						w: $(window).width(),
						h: $(window).height()
					},
					valid: true
				};
			}
			function getTooltipPosition() {
				updateCache();
				//Save as copy of the original preferences.
				var align = {
					vert: o.vAlign,
					hor: o.align
				};
				
				//Scroll position
				var scroll = {
					left: $(document.documentElement.body).scrollLeft(),
					top: $(document.documentElement.body).scrollTop()
				};
				
				//All the possible positions for the tooltip
				var pos = {
					top: {
						above: $this.cache.elmOffset.top - $this.cache.ttDim.h - o.distanceY + o.nudgeY, 
						below: $this.cache.elmOffset.top + $this.cache.elmDim.h + o.distanceY + o.nudgeY, 
						center: $this.cache.elmOffset.top - $this.cache.ttDim.h/2 + $this.cache.elmDim.h/2,
						flushTop: $this.cache.elmOffset.top,
						flushBottom: $this.cache.elmOffset.top + $this.cache.elmDim.h + $this.cache.ttDim.h,
						absTop: scroll.top  + o.windowMargin,
						absBottom: $this.cache.vp.h + scroll.top - $this.cache.ttDim.h - o.windowMargin,
						absCenter: scroll.top + $this.cache.vp.h/2 - $this.cache.ttDim.h/2
					},
					left: {
						left: $this.cache.elmOffset.left - $this.cache.ttDim.w - o.distanceX + o.nudgeX, 
						right: $this.cache.elmOffset.left + $this.cache.elmDim.w + o.distanceX + o.nudgeX, 
						center: $this.cache.elmOffset.left - $this.cache.ttDim.w/2 + $this.cache.elmDim.w/2, 
						flushLeft: $this.cache.elmOffset.left, 
						flushRight: $this.cache.elmOffset.left + $this.cache.elmDim.w - $this.cache.ttDim.w,
						absLeft: scroll.left + o.windowMargin,
						absRight: $this.cache.vp.w + scroll.left - $this.cache.ttDim.w - o.windowMargin,
						absCenter: scroll.left + $this.cache.vp.w/2 - $this.cache.ttDim.w/2
					}
				};
				
				//Booleans for whether there is space for the tooltip in a variety of positions.
				//Compares tooltip offset to the absolute top/left position keeping tooltip on-screen
				var space = {
					above: pos.top[align.vert] < pos.top.absTop ? false : true,
					below: pos.top[align.vert] > pos.top.absBottom ? false : true,
					left: pos.left[align.hor] < pos.left.absLeft ? false : true,
					right: pos.left[align.hor] > pos.left.absRight ? false : true
				};
				//Move the tooltip around if there isn't space in the current position.
				if ($this.cache.vp.h < $this.cache.ttDim.h) align.vert = 'absTop';
				else if (!space.above && !space.below && align.vert == 'below') {
					align.vert = 'absBottom';
				} else if ((align.vert === 'above' || align.vert === 'center') && !space.above) {
					align.vert = 'absTop';
				} else if ((align.vert === 'below' || align.vert === 'center') && !space.below) {
					align.vert = 'absBottom';
				}
				
				if (!space.left && !space.right) {
					align.hor = 'absLeft';
				} else if ((/^right|flushLeft|center$/i).test(align.hor) && !space.right) {
					align.hor = 'absRight';
				} else if ((/^left|flushRight|center$/i).test(align.hor) && !space.left) {			
					align.hor = 'absLeft';
				}
				return {
					left: pos.left[align.hor],
					top: pos.top[align.vert]
				};
			}
		});
	};
	//
	// private function for debugging
	//
	function cons(message) {
		if (window.console && window.console.log) {
			console.log(message);
		}
	};

	//
	// plugin defaults
	//
	$.fn.tt.defaults = {
		showEvent: 'mouseover',
		hideEvent: 'mouseout',
		align: 'flushLeft',
		vAlign: 'above',
		visibleOnScroll: true,
		windowMargin: 5,
		distanceX: 2,
		distanceY: 2,
		nudgeX: 0,
		nudgeY: 0,
		ttClass: 'tt_tip',
		activeClass: 'tt_active',
		ttIdPrefix: 'tt_',
		timeOut: 1000,
		delay: 250,
		fadeIn: 100,
		fadeOut: 250,
		zoom: false
	};
	//
	// end of closure
	//
})(jQuery);

// -----------------------------------------------------------------------
// ELASTIC TEXTAREA
// -----------------------------------------------------------------------
/**
*	@name							Elastic
*	@descripton						Elastic is Jquery plugin that grow and shrink your textareas automaticliy
*	@version						1.6.3
*	@requires						Jquery 1.2.6+
*
*	@author							Jan Jarfalk
*	@author-email					jan.jarfalk@unwrongest.com
*	@author-website					http://www.unwrongest.com
*
*	@licens							MIT License - http://www.opensource.org/licenses/mit-license.php
*/

(function(jQuery){ 
	jQuery.fn.extend({  
		elastic: function() {
		
			//	We will create a div clone of the textarea
			//	by copying these attributes from the textarea to the div.
			var mimics = [
				'paddingTop',
				'paddingRight',
				'paddingBottom',
				'paddingLeft',
				'fontSize',
				'lineHeight',
				'fontFamily',
				'width',
				'fontWeight'];
			
			return this.each( function() {
				
				// Elastic only works on textareas
				if ( this.type != 'textarea' ) {
					return false;
				}
				
				var $textarea	=	jQuery(this),
					$twin		=	jQuery('<div />').css({'position': 'absolute','display':'none','word-wrap':'break-word'}),
					lineHeight	=	parseInt($textarea.css('line-height'),10) || parseInt($textarea.css('font-size'),'10'),
					minheight	=	parseInt($textarea.css('height'),10) || lineHeight*3,
					maxheight	=	parseInt($textarea.css('max-height'),10) || Number.MAX_VALUE,
					goalheight	=	0,
					i 			=	0;
				
				// Opera returns max-height of -1 if not set
				if (maxheight < 0) { maxheight = Number.MAX_VALUE; }
					
				// Append the twin to the DOM
				// We are going to meassure the height of this, not the textarea.
				$twin.appendTo($textarea.parent());
				
				// Copy the essential styles (mimics) from the textarea to the twin
				var i = mimics.length;
				while(i--){
					$twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));
				}
				
				
				// Sets a given height and overflow state on the textarea
				function setHeightAndOverflow(height, overflow){
					curratedHeight = Math.floor(parseInt(height,10));
					if($textarea.height() != curratedHeight){
						$textarea.css({'height': curratedHeight + 'px','overflow':overflow});
						
					}
				}
				
				
				// This function will update the height of the textarea if necessary 
				function update() {
					
					// Get curated content from the textarea.
					var textareaContent = $textarea.val().replace(/&/g,'&amp;').replace(/  /g, '&nbsp;').replace(/<|>/g, '&gt;').replace(/\n/g, '<br />');

					var twinContent = $twin.html();
					
					if(textareaContent+'&nbsp;' != twinContent){
					
						// Add an extra white space so new rows are added when you are at the end of a row.
						$twin.html(textareaContent+'&nbsp;');
						
						// Change textarea height if twin plus the height of one line differs more than 3 pixel from textarea height
						if(Math.abs($twin.height()+lineHeight - $textarea.height()) > 3){
							
							var goalheight = $twin.height()+lineHeight;
							if(goalheight >= maxheight) {
								setHeightAndOverflow(maxheight,'auto');
							} else if(goalheight <= minheight) {
								setHeightAndOverflow(minheight,'hidden');
							} else {
								setHeightAndOverflow(goalheight,'hidden');
							}
							
						}
						
					}
					
				}
				
				// Hide scrollbars
				$textarea.css({'overflow':'hidden'});
				
				// Update textarea size on keyup
				$textarea.keyup(function(){ update(); });
				
				// And this line is to catch the browser paste event
				$textarea.live('input paste',function(e){ setTimeout( update, 250); });				
				
				// Run update once when elastic is initialized
				update();
				
			});
			
        } 
    }); 
})(jQuery);