/*—~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ T O O L   F U N C T I O N.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ J Q U E R Y.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

	//~~~~~~~~~~~~~ JQUERY-UI DATE/TIME PICKER — FRENCH TRANSLATION.
	jQuery(function($) {
		if (jQuery.ui) {
			// Date.
			$.datepicker.regional['fr'] = {
				closeText: 'Fermer',
				prevText: '&#x3c;Préc',
				nextText: 'Suiv&#x3e;',
				currentText: 'Maintenant',
				monthNames: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
				monthNamesShort: ['Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Jun', 'Jul', 'Aoû', 'Sep', 'Oct', 'Nov', 'Déc'],
				dayNames: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'],
				dayNamesShort: ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'],
				dayNamesMin: ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa'],
				dateFormat: 'dd/mm/yy', firstDay: 1,
				isRTL: false			
			};
			$.datepicker.setDefaults($.datepicker.regional['fr']);
			$.datepicker.setDefaults({dateFormat: 'yy-mm-dd'});  // 'yy-mm-dd'
			// Time.
			$.timepicker.regional['fr'] = {
				timeOnlyTitle: 'Choisissez l’heure',
				timeText: 'Horaire',
				hourText: 'Heures',
				minuteText: 'Minutes',
				secondText: 'Secondes',
				currentText: 'Maintenant',
				closeText: 'Fermer',
				ampm: false
			};
			$.timepicker.setDefaults($.timepicker.regional['fr']);
			$.timepicker.setDefaults({timeFormat: 'hh:mm:ss'});
		}
	});

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JQUERY EXTEND — FIND TEXT NODES.
	(function($) {
		$.fn.textNodes = function() {
			var ret = [];
			this.each(function() {
				var fn = arguments.callee;
				$(this).contents().each(function() {
					if ( this.nodeType == 3)
						ret.push(this);
					else
						fn.apply($(this))
				});
			});
			return $(ret);
		};
	})(jQuery);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JQUERY EXTEND — FORM TO OBJECT.
	(function($) {
		$.fn.serializeObject = function() {
			var o = {};
			var a = this.serializeArray();
			$.each(a, function() {
				if (o[this.name]) {
					if (!o[this.name].push) {
						o[this.name] = [o[this.name]];
					}
					o[this.name].push(this.value || '');
				} else {
					o[this.name] = this.value || '';
				}
			});
			return o;
		};
	})(jQuery);

	//~~~~~~~~~~~~~~~~~~~ JQUERY EXTEND — EQUALIZE ELEMENTS HEIGHTS.
	(function ($) {
		$.fn.equalHeight = function() {
			var height = 0,
			highest = 0,
			reset = $.browser.msie ? '1%' : 'auto';
			return this.css('height', reset).each(function() {
				height = Math.max(height, this.offsetHeight);
				if (height > highest)  highest = height;
			}).css('height', height).each(function() {
				var h = this.offsetHeight;
				if (h > height)  $(this).css('height', height-(h-height));
			});
		};
	})(jQuery);

	//~~~~~~~~~~~~~~~~~~~ JQUERY EXTEND — EQUALIZE CHILDREN HEIGHTS.
	(function($) {
		$.fn.equalHeightChildren = function(px) {
			$(this).each(function() {
				var currentTallest = 0;
				$(this).children().each(function(i) {
					if ($(this).height() > currentTallest)  currentTallest = $(this).height();
				});
				if (!px || !Number.prototype.pxToEm) currentTallest = currentTallest.pxToEm();
				if ($.browser.msie && $.browser.version == 6.0)  $(this).children().css({'height': currentTallest});
				$(this).children().css({'min-height': currentTallest}); 
			});
			return this;
		};
	})(jQuery);

	//~~~~~~~~~~~~~~~~~~~ JQUERY EXTEND — ELEMENTS SMALLEST/BIGGEST.
	(function($) {
		$.fn.tallest = function()       { return this._extremities({aspect:'height', max:true })[0] };
		$.fn.tallestSize = function()   { return this._extremities({aspect:'height', max:true })[1] };
		$.fn.shortest = function()      { return this._extremities({aspect:'height', max:false})[0] };
		$.fn.shortestSize = function()  { return this._extremities({aspect:'height', max:false})[1] };
		$.fn.widest = function()        { return this._extremities({aspect:'width',  max:true })[0] };
		$.fn.widestSize = function()    { return this._extremities({aspect:'width',  max:true })[1] };
		$.fn.thinnest = function()      { return this._extremities({aspect:'width',  max:false})[0] };
		$.fn.thinnestSize = function()  { return this._extremities({aspect:'width',  max:false})[1] };
		$.fn._extremities = function(options) {
			var defaults = {
				aspect : 'height',
				max : true
			};
			options = $.extend(defaults, options);	
			if (this.length < 2)  return [this, this[options.aspect]()];
			var bestIndex = 0,
			bestSize = this.eq(0)[options.aspect](),
			thisSize;
			for (var i=1; i<this.length; ++i) {
				thisSize = this.eq(i)[options.aspect]();
				if ((options.max && thisSize > bestSize) || (!options.max && thisSize < bestSize)) {
					bestSize = thisSize;
					bestIndex = i;
				}
			}
			return [this.eq(bestIndex), bestSize];
		};
	})(jQuery);

	//~~~~~~~~~~~~~~~~~~~~~~ JQUERY EXTEND — ELEMENTS DIMENSION SUM.
	(function($) {
		$.fn.sumWidth  = function() { return this.sum('width')  };
		$.fn.sumHeight = function() { return this.sum('height') };
		$.fn.sum = function(aspect) {
			var sum = 0;
			$(this).each(function() {
				sum += (aspect=='height') ? $(this).outerHeight() : $(this).outerWidth();
			});
			return sum;
		};
	})(jQuery);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JQUERY EXTEND — CENTER ELEMENT.
	(function($) {
		$.fn.extend({
			center: function(options) {
				var options = $.extend({ // Default values
					inside: window,  // element, center into window
					transition: 0,  // millisecond, transition time
					shiftX: 0,
					shiftY: 0,
					minX: 0,  // pixel, minimum left element value
					minY: 0,  // pixel, minimum top element value
					withScrolling: true,  // booleen, take care of the scrollbar (scrollTop)
					vertical: true,  // booleen, center vertical
					horizontal: true  // booleen, center horizontal
				}, options);
				return this.each(function() {
					var props = {position:'absolute'};
					if (options.vertical) {
						var top = ($(options.inside).height() - $(this).outerHeight()) / 2;
						if (options.withScrolling) top += $(options.inside).scrollTop() || 0;
						top = (top+options.shiftY > options.minY ? top+options.shiftY : options.minY);
						$.extend(props, {top: top+'px'});
					}
					if (options.horizontal) {
						var left = ($(options.inside).width() - $(this).outerWidth()) / 2;
						if (options.withScrolling) left += $(options.inside).scrollLeft() || 0;
						left = (left+options.shiftX > options.minX ? left+options.shiftX : options.minX);
						$.extend(props, {left: left+'px'});
					}
					if (options.transition > 0) $(this).animate(props, options.transition);
					else $(this).css(props);
					return $(this);
				});
			}
		});
	})(jQuery);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JQUERY EXTEND — SCROLLBAR WIDTH.
	(function($) {
		$.scrollbarWidth = function() {
			if (!$._scrollbarWidth) {
				var $body = $('body');
				var w = $body.css('overflow', 'hidden').width();
				$body.css('overflow', 'scroll');
				w -= $body.width();
				if (!w) w = $body.width()-$body[0].clientWidth;
				$body.css('overflow', '');
				$._scrollbarWidth = w;
			}
			return $._scrollbarWidth;
		};
	})(jQuery);





/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ P E R S O N A L   T O O L S.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TAB / RETURN.
	function tab(t) {
		var r = t || 1;
		return new Array(t+1).join("\t");
	}
	function rn(r) {
		var r = r || 1;
		return new Array(r+1).join("\r\n");
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VAR DUMP.
	function varDump(arr, level) {
		var dumped_text = '';
		if (!level) level = 0;
		var level_padding = '';
		for (var j=0;j<level+1;j++) level_padding += '    ';
		if (typeof(arr) == 'object') {
			for(var item in arr) {
				var value = arr[item];
				if (typeof(value) == 'object') {
					dumped_text += level_padding + "'" + item + "' ...\n";
					dumped_text += varDump(value,level+1);
				} else {
					dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
				}
			}
		} else {
			dumped_text = '===>'+arr+'<===('+typeof(arr)+')';
		}
		return dumped_text;
	}

	//~~~~~~~~~~~~~~~~~~~~~~ CHECK MOBILE (before jquery dom ready).
	function userMobile() {
		var userAgent = navigator.userAgent.toLowerCase();
		if ((userAgent.search(/android|avantgo|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris/i) != -1) || (userAgent.search(/kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)|plucker|pocket|psp/i) != -1) || (userAgent.search(/symbian|treo|up.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i) != -1))
			return true;
		else if ($.browser.msie && parseInt($.browser.version)<9)
			return true;
		else
			return false;
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EMAIL ADDRESS VALIDITY.
	function emailCheck(str) {
		var regExp = /^\w([-_.]?\w)*@\w([-_.]?\w)*\.([a-zA-Z]{2,4})$/;
		return (regExp.test(str));
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ URL-REWRITING.
	function urlRewriting(str, cut) {
		str = (cut) ? stringCut(str, cut) : str;
		str = str.replace(/\s/g, " ");
		str = str.replace(/['’‘´'\`]+/g, "'");
		str = str.replace(/[«»“”\"<{\(\[\]\)}>–—•]+/g, "");
		str = str.replace(/\&/g, "and");
		str = str.replace(/œ/g, "oe");
		str = htmlEntities(str, "HTML_ENTITIES", "ENT_NOQUOTES");
		str = str.replace(/&([a-z])[a-z]+;/gi, "$1");
		str = str.toLowerCase();
		str = str.replace(/\b[a-z]?\'/g, "-");
		str = str.replace(/[^0-9a-z]+/g, "-");
		return trim(str, "-");
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IS EMPTY VARIABLE.
	function empty(variable) {
		var key;
		if (variable === "" || variable === 0 || variable === "0" || variable === null || variable === false || variable == "undefined" || typeof variable == "undefined")
			return true;
		if (typeof variable == 'object') {
			for (key in variable)
				return false;
			return true;
		}
		return false;
	}


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ARRAY – IN.
	function in_array(needle, haystack, argStrict) {
		var key = '',
		strict = !! argStrict;
		if (strict) {
			for (key in haystack) {
				if (haystack[key] === needle)
					return true;
			}
		} else {
			for (key in haystack) {
				if (haystack[key] == needle)
					return true;
				}
		}
		return false;
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ARRAY – IMPLODE.
	function implode(glue, pieces) {
		var i='', retVal='', tGlue='';
		if (arguments.length === 1) {
			pieces = glue;
			glue = '';
		}
		if (typeof(pieces) === 'object') {
			if (pieces instanceof Array)
				return pieces.join(glue);
			else {
				for (i in pieces) {
					retVal += tGlue + pieces[i];
					tGlue = glue;
				}
				return retVal;
			}
		}
		else
			return pieces;
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING – EXPLODE.
	function explode(delimiter, string, limit) {
		var emptyArray = {0: ''};
		if (arguments.length < 2 || typeof arguments[0] == 'undefined' || typeof arguments[1] == 'undefined')
			return null;
		if (delimiter === '' || delimiter === false || delimiter === null )
			return false;
		if (typeof delimiter == 'function' || typeof delimiter == 'object' || typeof string == 'function' || typeof string == 'object')
			return emptyArray;
		if (delimiter === true)
			delimiter = '1';
		if (!limit)
			return string.toString().split(delimiter.toString());
		else {
			var splitted = string.toString().split(delimiter.toString());
			var partA = splitted.splice(0, limit - 1);
			var partB = splitted.join(delimiter.toString());
			partA.push(partB);
			return partA;
		}
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING – CUT.
	function strCut(str, len, more) {
		if (str.length > len) {
			if (str.match(/\s/)) {
				while (str.substr(len, 1) != ' ')
					len--;
			}
			str = str.substr(0, len)+(more ? more : '');
		}
		return str;
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING – UNSHIFT.
	function strUnshift(str, fill, len) {
		for (var i=str.length; i<len; i++)
			str = fill+str;
		return str;
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING – UCFIRST.
	function strUcfirst(str) {
		return str.charAt(0).toUpperCase()+str.substr(1);
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING – UCWORDS.
	function strUcwords(str) {
		return (str).replace(/^(.)|\s(.)/g, function ($1) {
			return $1.toUpperCase();
		});
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING – CAMEL CASE.
	function strCamelCase(str) {
		str = trim(str.toLowerCase());
		return str.replace(/([^0-9a-zA-Z])(\w)/g, function(t,a,b) { return b.toUpperCase(); });
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING – TRIM.
	function trim(str, charlist) {
		var whitespace, l=0, i=0;
		str += '';
		if (!charlist) {
			whitespace = " \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000";
		} else {
			charlist += '';
			whitespace = charlist.replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '$1');
		}
		l = str.length;
		for (i=0; i<l; i++) {
			if (whitespace.indexOf(str.charAt(i)) === -1) {
				str = str.substring(i);
				break;
			}
		}
		l = str.length;
		for (i=l-1; i>=0; i--) {
			if (whitespace.indexOf(str.charAt(i)) === -1) {
				str = str.substring(0, i + 1);
				break;
			}
		}
		return whitespace.indexOf(str.charAt(0)) === -1 ? str : '';
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING – UCFIRST.
	function utf8Decode(str) {
		var arr=[], i=0, ac=0, c1=0, c2=0, c3=0;
		str += '';
		while (i < str.length) {
			c1 = str.charCodeAt(i);
			if (c1 < 128) {
				arr[ac++] = String.fromCharCode(c1);
				i++;
			} else if ((c1 > 191) && (c1 < 224)) {
				c2 = str.charCodeAt(i+1);
				arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
				i += 2;
			} else {
				c2 = str.charCodeAt(i+1);
				c3 = str.charCodeAt(i+2);
				arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}
		}
		return arr.join('');
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ NUMBER – MTRAND.
	 Math.mtrand = function(min, max) {
		var argc = arguments.length;
		if (argc === 0) {
			min = 0;
			max = 2147483647;
		} else if (argc === 1) {
			throw new Error('Warning: mt_rand() expects exactly 2 parameters, 1 given');
		}
		return Math.floor(Math.random() * (max-min+1)) + min;
	}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE-TIME CLOCK.
	function clockCompute() {
		tagObj = $('span#dateCurrent');
		if (!tagObj.date) {
			tagObj.date = trim(tagObj.text().replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:\-\_\.\s])+/g, " ")).split(" ");
			tagObj.dateHours = parseFloat(tagObj.date[0]);
			tagObj.dateMinutes = parseFloat(tagObj.date[1]);
			tagObj.dateSeconds = parseFloat(tagObj.date[2]);
		}
		tagObj.dateSeconds += 1;
		if (tagObj.dateSeconds == 60) {
			tagObj.dateSeconds = 0;
			tagObj.dateMinutes += 1;
			if (tagObj.dateMinutes == 60) {
				tagObj.dateMinutes = 0;
				tagObj.dateHours = (tagObj.dateHours == 24) ? 0 : (tagObj.dateHours+1);
			}
		}
		tagObj.text(strUnshift(tagObj.dateHours.toString(),'0',2)+"."+strUnshift(tagObj.dateMinutes.toString(),'0',2)+"."+strUnshift(tagObj.dateSeconds.toString(),'0',2)+" _ "+tagObj.date[3]+"."+tagObj.date[4]+"."+tagObj.date[5]);
	}

