/* Classe Core */
/**
 * Create an anonymous (lambda-style) function
 * @param {Object} args
 * @param {Object} code
 *     example 1: f = create_function('a, b', "return (a + b);");
 *     example 1: f(1, 2);
 *     returns 1: 3
 */
function create_function(args, code) {
	eval('var _oFunctionObject = function (' + args + ') { ' +  code + '}');
	return _oFunctionObject;
}
/**
 * Return TRUE if the given function has been defined
 * @param {Object} function_name
 *     example 1: function_exists('isFinite');
 *     returns 1: true
 */
function function_exists( function_name ) {
    if (typeof function_name == 'string')
        return (typeof window[function_name] == 'function');
    else
        return (function_name instanceof Function);
}
/**
 * Include a Js file 
 * @param {Object} filename
 *     example 1: include('http://www.phpjs.org/js/phpjs/_supporters/pj_test_supportfile_2.js');
 *     returns 1: 1
 */
function include(filename) {
    var js = document.createElement('script');
    js.setAttribute('type', 'text/javascript');
    js.setAttribute('src', filename);
    js.setAttribute('defer', 'defer');
    document.getElementsByTagName('HEAD')[0].appendChild(js);

    // save include state for reference by include_once
    var cur_file = {};
    cur_file[window.location.href] = 1;

    if (!window.php_js) window.php_js = {};
    if (!window.php_js.includes) window.php_js.includes = cur_file;
    if (!window.php_js.includes[filename]) 
        window.php_js.includes[filename] = 1;
    else 
        window.php_js.includes[filename]++;
    return window.php_js.includes[filename];
}
/**
 * Like Include but check if it isn't already loaded
 * @param {Object} filename
 *    depends on: include
 *     example 1: include_once('http://www.phpjs.org/js/phpjs/_supporters/pj_test_supportfile_2.js');
 *     returns 1: true
 */
function include_once( filename ) {
    var cur_file = {};
    cur_file[window.location.href] = 1;

    if (!window.php_js) window.php_js = {};
    if (!window.php_js.includes) window.php_js.includes = cur_file;
    if (!window.php_js.includes[filename]) 
        if(include(filename))
            return true;
        
    else
        return true;
    
}
/**
 * 
 * @param {Object} filename
 * -    depends on: fileGetContents
 *     example 1: require('http://www.phpjs.org/js/phpjs/_supporters/pj_test_supportfile_2.js');
 *     returns 1: 2
 */
function require(filename){
  	// 
	
	var js_code = fileGetContents(filename);
	var script_block = document.createElement('script');
	script_block.type = 'text/javascript';
	var client_pc = navigator.userAgent.toLowerCase();
	if ((client_pc.indexOf("msie") != -1) && (client_pc.indexOf("opera") == -1)) {
		script_block.text = js_code;
	}
	else {
		script_block.appendChild(document.createTextNode(js_code));
	}
	
	if (typeof(script_block) != "undefined") {
		document.getElementsByTagName("head")[0].appendChild(script_block);
		
		// save include state for reference by include_once and require_once()
		var cur_file = {};
		cur_file[window.location.href] = 1;
		
		if (!window.php_js) 
			window.php_js = {};
		if (!window.php_js.includes) 
			window.php_js.includes = cur_file;
		
		if (!window.php_js.includes[filename]) {
			window.php_js.includes[filename] = 1;
		}
		else {
			// Use += 1 because ++ waits until AFTER the original value is returned to increment the value.
			return window.php_js.includes[filename] += 1;
		}
	}
}
/**
 * 
 * @param {Object} filename
 */
function require_once(filename) {
    // The require_once() statement includes and evaluates the specified file during
    // the execution of the script. This is a behavior similar to the require()
    // statement, with the only difference being that if the code from a file has
    // already been included, it will not be included again.  See the documentation for
    // require() for more information on how this statement works.
   	// -    depends on: require
    // *     example 1: require_once('http://www.phpjs.org/js/phpjs/_supporters/pj_test_supportfile_2.js');
    // *     returns 1: true

    var cur_file = {};
    cur_file[window.location.href] = 1;

    // save include state for reference by include_once and require_once()
    if (!window.php_js) window.php_js = {};
    if (!window.php_js.includes) window.php_js.includes = cur_file;
    if (!window.php_js.includes[filename]) {
        if (require(filename)) {
            return true;
        }
    } else {
        return true;
    }
}
/**
 * Returns an array with the names of included or required files
 *     example 1: get_included_files();
 *     returns 1: ['http://kevin.vanzonneveld.net/pj_tester.php']
 */	
function getIncludedFiles() {
    var cur_file = {};
    cur_file[window.location.href] = 1;
    if(!__php_js) __php_js = {};
    if(!__php_js.includes) __php_js.includes = cur_file;

    var includes = new Array();
    var i = 0;
    for(var key in __php_js.includes){
        includes[i] = key;
        i++;
    }

    return includes;
}
/**
 * Stop the current JS execution. Don't Stop the others Scripts
 * @param {String} status
 */
function exit( status ) {
    var i;
 
    if (typeof status === 'string') {
        alert(status);
    }
 
    window.addEventListener('error', function (e) {e.preventDefault();e.stopPropagation();}, false);
 
    var handlers = [
        'copy', 'cut', 'paste',
        'beforeunload', 'blur', 'change', 'click', 'contextmenu', 'dblclick', 'focus', 'keydown', 'keypress', 'keyup', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'resize', 'scroll',
        'DOMNodeInserted', 'DOMNodeRemoved', 'DOMNodeRemovedFromDocument', 'DOMNodeInsertedIntoDocument', 'DOMAttrModified', 'DOMCharacterDataModified', 'DOMElementNameChanged', 'DOMAttributeNameChanged', 'DOMActivate', 'DOMFocusIn', 'DOMFocusOut', 'online', 'offline', 'textInput',
        'abort', 'close', 'dragdrop', 'load', 'paint', 'reset', 'select', 'submit', 'unload'
    ];
    
    function stopPropagation (e) {
        e.stopPropagation();
        // e.preventDefault(); // Stop for the form controls, etc., too?
    }
    for (i=0; i < handlers.length; i++) {
        window.addEventListener(handlers[i], stopPropagation, true);
    }
    
    throw '';
}
/**
 * Alias of exit();
 * @param {Object} status
 */
function die(status){
	return exit(status);
}
/**
 * Return the content of a file
 * Using XMLHttpRequest via Mootools 1.2
 * - Depends of Request 
 * @param {Object} file
 */
function fileGetContents(file){
	var getIt = new Request({
		method: 'get',
		url : file,
		onComplete: function(response){
			return response;
		},
		onFailure: function(){
			alert("FileGetContents Failed");
			return null;
		}
	}).send();
}
/**
 * Reads entire file into an array
 * @param {Object} url
 * - Depends of fileGetContents
 */
function getFile(url) {
    return fileGetContents(url).split('\n');
}
/**
 * Check if a class is defined
 * @param {Object} cls
 * @return {Boolean}
 *     example 1: function class_a() {this.meth1 = function() {return true;}};
 *     example 1: var instance_a = new class_a();
 *     example 1: class_exists('class_a');
 *     returns 1: true
 */
function classExists (cls) {
    var i;
    cls = window[cls]; // Note: will prevent inner classes
 
    if (typeof cls !== 'function') {return false;}
 
    for (i in cls.prototype) {
        return true;
    }
    for (i in cls) { // If static members exist, then consider a "class"
        if (i !== 'prototype') {
            return true;
        }
    }
    if (cls.toSource && cls.toSource().match(/this\./)) { 
        // Hackish and non-standard but can probably detect if setting
        // a property (we don't want to test by instantiating as that
        // may have side-effects)
        return true;
    }
    
    return false;
}
/**
 * Check if a method exists in an object
 * @param {Object} obj
 * @param {Object} method
 *     example 1: function class_a() {this.meth1 = function() {return true;}};
 *     example 1: var instance_a = new class_a();
 *     example 1: method_exists(instance_a, 'meth1');
 *     returns 1: true
 *     example 2: function class_a() {this.meth1 = function() {return true;}};
 *     example 2: var instance_a = new class_a();
 *     example 2: method_exists(instance_a, 'meth2');
 *     returns 2: false
 */
function methodExists (obj, method) {
    if (typeof obj === 'string') {
        return window[obj] && typeof window[obj][method] === 'function'
    }
 
    return typeof obj[method] === 'function';
}
/**
 * Extension de la classe Array
 * @author 58062
 * @from php.js
 */

function ExtObj(){};
/**
 * Check if value exist in the array
 * @param {Object} needle : the value searched
 * @param {Object} strict optionnal |true| if you want to check the type 
 * @return {Bool} 
 */
ExtObj.has = function (obj, needle, strict) {
		var found = false, key, strict = !!strict;
		for (key in obj) {
		  if ((strict && obj[key] === needle) || (!strict && obj[key] == needle)) {
		      found = true;
		      break;
		  }
		}
	 	return found;
	};
/**
 * Change the case of the array keys
 * @param optional case CASE_LOWER|CASE_UPPER
 * example 1: array_change_key_case(42);
 *     returns 1: false
 *     example 2: array_change_key_case([ 3, 5 ]);
 *     returns 2: {0: 3, 1: 5}
 *     example 3: array_change_key_case({ FuBaR: 42 });
 *     returns 3: {"fubar": 42}
 *     example 4: array_change_key_case({ FuBaR: 42 }, 'CASE_LOWER');
 *     returns 4: {"fubar": 42}
 *     example 5: array_change_key_case({ FuBaR: 42 }, 'CASE_UPPER');
 *     returns 5: {"FUBAR": 42}
 *     example 6: array_change_key_case({ FuBaR: 42 }, 2);
 *     returns 6: {"FUBAR": 42}
 */
ExtObj.changeKeyCase = function (obj) {
	    var case_fn, tmp_ar = new Object, argc = arguments.length, argv = arguments, key;
	
	    if (obj instanceof Array) {
	        return obj;
	    }
	
	    if (obj instanceof Object) {
	        if( argc == 1 || argv[1] == 'CASE_LOWER' || argv[1] == 0 ){
	            case_fn = "toLowerCase";
	        } else{
	            case_fn = "toUpperCase";
	        }
	        for (var key in obj) {
	            tmp_ar[key[case_fn]()] = obj[key];
	        }
	        return tmp_ar;
	    }
	    return false;
	};
/**
 * Return an array using the values of the array as keys and their frequency as values
 * @return {Array} 
 */
ExtObj.countValues = function ( array ) {
	    var tmp_arr = {}, key = '', t = '';
	    
	    var __getType = function(obj) {
	        // Objects are php associative arrays.
	        var t = typeof obj;
	        t = t.toLowerCase();
	        if (t == "object") {
	            t = "array";
	        }
	        return t;
	    }    
	 	var __countValue = function (value) {
	        switch (typeof(value)) {
	            case "number":
	                if (Math.floor(value) != value) {
	                    return;
	                }
	            case "string":
	                if (value in this) {
	                    ++this[value];
	                } else {
	                    this[value] = 1;
	                }
	        }
	    };
	    t = __getType(array);
	    if (t == 'array') {
	        for ( key in array ) {
	            __countValue.call(tmp_arr, array[key]);
	        }
	    } 
	    return tmp_arr;
	};
/**
 * Compares the array with others and return the difference
 * @param {Array} any array you want
 * @return {Array}
 *     example 1: 	myArray = ['Kevin', 'van', 'Zonneveld'];
 *     				myArray.diff(['van', 'Zonneveld']);
 *     returns 1: ['Kevin']
 */
ExtObj.diff = function (obj) {
	    var arr_dif = [], i = 1, argc = arguments.length, argv = arguments, key, key_c, found=false, cntr=0;
		if (argc == 0)
			return false;		
	    // loop through 1st array
	    for ( key in obj ){
	        // loop over other arrays
	        for (i = 0; i< argc; i++){
	            // find in the compare array
	            found = false;
	            for (key_c in argv[i]) {
	                if (argv[i][key_c] == obj[key]) {
	                    found = true;
	                    break;
	                }
	            }
	
	            if(!found){
	                arr_dif[cntr] = obj[key];
	                cntr++;
	            }
	        }
	    }
	
	    return arr_dif;
	};
/**
 * Compares array with others. Unlike Array.diff() the array keys are used in the comparision
 * @param {Array} any array you want
 * @return {Array}
 *     example 1: 	myArray = {0: 'Kevin', 1: 'van', 2: 'Zonneveld'};
 *     				myArray.diffAssoc({0: 'Kevin', 4: 'van', 5: 'Zonneveld'});
 *     returns 1: {1: 'van', 2: 'Zonneveld'}
 */
ExtObj.diffAssoc = function(obj) {
	    var arr_dif = {}, i = 1, argc = arguments.length, argv = arguments, key, key_c, found=false;
		if (argc == 0)
			return false;
	    // input sanitation
		for (var i=0;i<argc;i++)
			if( !argc[i] || (argc[i].constructor !== Array && typeof argc[i] != 'object' && typeof argc[i] != 'array') )
	        	return false;
	    
	   // loop through 1st array
	    for ( key in obj ){
	        // loop over other arrays
	        for (i = 0; i< argc; i++){
	            // find in the compare array
	            found = false;
	            if(argv[i][key]){
	                found = true;
	                break;
	            }
	
	            if(!found){
	                arr_dif[key] = obj[key];
	            }
	        }
	    }
	
	    return arr_dif;
	};
/**
 * Computes the difference of arrays using keys for comparison
 * @param {Array} any array you want
 * @return {Array} 
 *     example 1: 	myArray = {red: 1, green: 2, blue: 3, white: 4};
 *     				myArray.diffKey({red: 5});
 *     returns 1: {"green":2, "blue":3, "white":4}
 *     example 2: 	myArray = {red: 1, green: 2, blue: 3, white: 4};
 *     myArray.diffKey({red: 5}, {green: 6, blue: 7});
 *     returns 2: {"white":4}
 */
ExtObj.diffKey =  function (obj) {
	    var tpm_ar = new Object(), argc = arguments.length, argv = arguments, key, argidx, other;
	
	    for (key in obj) {
	        tpm_ar[key] = obj[key];
	    }
	    for (argidx = 0; argidx < argc; ++argidx) {
	        other = argv[argidx];
	
	        if (other instanceof Object) {
	            for (key in other) {
	                delete tpm_ar[key];
	            }
	        }
	    }
	
	    return tpm_ar;
	};
/**
 * Checks if the given key or index exists in the array
 * @param {Object} key
 * @return {Bool}
 */
ExtObj.keyExists =  function (obj, key ) {
	    // input sanitation
	    if( !obj || (obj.constructor !== Array && obj.constructor !== Object) )
	        return false;
	
	    return key in obj;
	};
/**
 * Return all the keys of an array
 * @param {Object} search_value if specified, then only keys containing these values are returned
 * @param {Object} strict if search on, check the strict comparison
 * @return {Array}
 *     example 1: 	myArray = {firstname: 'Kevin', surname: 'van Zonneveld'};
 *     				myArray.keys();
 *     returns 1: {0: 'firstname', 1: 'surname'}
 */	
ExtObj.keys =  function(obj, search_value, strict ) {
	    var tmp_arr = new Array(), strict = !!strict, include = true, cnt = 0;
	
	    for ( key in obj ){
	        include = true;
	        if ( search_value != undefined ) {
	            if( strict && obj[key] !== search_value ){
	                include = false;
	            } else if( obj[key] != search_value ){
	                include = false;
	            }
	        }
	
	        if( include ) {
	            tmp_arr[cnt] = key;
	            cnt++;
	        }
	    }
	
	    return tmp_arr;
	};
/**
 * Searches the array for a given value and returns the corresponding key if successful
 * @param {Object} needle
 * @param {Bool} strict
 *     example 1: 	myArray = {firstname: 'kevin', middle: 'van', surname: 'zonneveld'};
 *     				myArray.search('zonneveld');
 *     returns 1: 'surname'
 */
ExtObj.search = function (obj, needle, strict ) {
	    var strict = !!strict;
	
	    for(var key in obj){
	        if( (strict && obj[key] === needle) || (!strict && obj[key] == needle) ){
	            return key;
	        }
	    }
	
	    return false;
	};
/**
 * Removes duplicate values from an array
 * @return {Array}
 *     example 1:	myArray = ['Kevin','Kevin','van','Zonneveld','Kevin'];
 *     				myArray.unique();
 *     returns 1: ['Kevin','van','Zonneveld']
 *     example 2: 	myArray = {'a': 'green', 0: 'red', 'b': 'green', 1: 'blue', 2: 'red'};
 *     				myArray.unique();
 *     returns 2: {'a': 'Kevin', 0: 'van', 1: 'Zonneveld'}
 */
ExtObj.unique = function (obj) {
	    var p, i, j, tmp_arr = obj;
	    for(i = tmp_arr.length; i;){
	        for(p = --i; p > 0;){
	            if(tmp_arr[i] === tmp_arr[--p]){
	                for(j = p; --p && tmp_arr[i] === tmp_arr[p];);
	                i -= tmp_arr.splice(p + 1, j - p).length;
	            }
	        }
	    }
	    return tmp_arr;
	};
/**
 * Return all the values of an array
 * @return {Array}
 *     example 1: 	myArray = {firstname: 'Kevin', surname: 'van Zonneveld'};
 *     				myArray.values();
 *     returns 1: {0: 'Kevin', 1: 'van Zonneveld'}
 */
ExtObj.values =  function (obj) {
	    var tmp_arr = new Array(), cnt = 0;
	
	    for ( key in obj ){
	        tmp_arr[cnt] = obj[key];
	        cnt++;
	    }
	    return tmp_arr;
	};
/**
 * Set the internal pointer of an array to its first element
 *     example 1: 	myArray = {0: 'Kevin', 1: 'van', 2: 'Zonneveld'};
 *     				myArray.reset();
 *     returns 1: 'Kevin'
 */
ExtObj.reset =  function (obj) {
	    
	
	    var first_elm, key;
	
	    if (obj.constructor == Array){
	        first_elm = array[0];
	    } else {
	        for (key in obj){
	            first_elm = obj[key];
	            break;
	        }
	    }
	
	    return first_elm;
	};
/**
 * Set the internal pointer of an array to its last element
 *     example 1: 	myArray = {0: 'Kevin', 1: 'van', 2: 'Zonneveld'};
 *     				myArray.end();
 *     returns 1: 'Zonneveld'
 *     example 2: 	myArray = ['Kevin', 'van', 'Zonneveld'];
 *     				myArray.end();
 *     returns 2: 'Zonneveld'
 */
ExtObj.end = function (obj) {
	    var last_elm, key;
	    
	    // The native .pop() method didn't not work with objects (associative arrays)
	    // We need that for PHP compatibility
	    
	    if (this.constructor == Array){
	        last_elm = obj[(obj.length-1)];
	    } else {
	        for (key in obj){
	            last_elm = obj[key];
	        }
	    }
	    
	    return last_elm;
	};
/**
 * Apply a user function to every member of an array
 * @param {Object} funcname
 * @param {Object} userdata
 */
ExtObj.walk = function (obj, funcname, userdata) {
	   	var key; 
	    
	    if (typeof obj != 'object'){
	        return false;
	    }
	    
	    for (key in obj){
	        if (typeof (userdata) != 'undefined'){
	            eval (funcname + '( obj [key] , key , userdata  )' );
	        } else {
	            eval (funcname + '(  userdata ) ');
	        }
	    }
	    
	    return true;
	};
Array.implement({
	/**
	 * Pick one or more random entries out of an array
	 * @param {Object} num_req : number of entries you want
	 * @return {Array} 
	 */
	rand: function (num_req ) {
		var Indexes = [];
	    var Ticks = num_req || 1;
	    var checkDuplicate = function ( input, value ) {
	        var Exist = false, Index = 0;
	        while ( Index < input.length ) {
	            if ( input [ Index ] === value ) {
	                Exist = true;
	                break;
	            }
	            Index++;
	        }
	        return Exist;
	    };
	
	    if ( this instanceof Array && Ticks <= this.length ) {
	        while ( true ) {
	            var Rand = Math.floor ( ( Math.random ( ) * this.length ) );
	            if ( Indexes.length === Ticks ) { break; }
	            if ( !checkDuplicate ( Indexes, Rand ) ) { Indexes.push ( Rand ); }
	        }
	    } 
		else {
			
	        Indexes = null;
	    }
	
	    return ( ( Ticks == 1 ) ? Indexes.join ( ) : Indexes );
	},
	
	
	has: function (needle, strict) {
		return ExtObj.has(this, needle, strict);
	},
	
	
	changeKeyCase: function () {
	    return ExtObj.changeKeyCase(this);
	},
	
	/**
	 * Split an array into chunks
	 * @param {Object} size
	 * @return {Array}
	 * example 1: 	myArray = ['Kevin', 'van', 'Zonneveld'];
	 * 				myArray.chunk(2);
	 * returns 1: {0 : {0: 'Kevin', 1: 'van'} , 1 : {0: 'Zonneveld'}}
	 */
	chunk: function ( size ) {
	    for(var x, i = 0, c = -1, l = this.length, n = []; i < l; i++){
	        (x = i % size) ? n[c][x] = this[i] : n[++c] = [this[i]];
	    }
	    return n;
	},
	
	
	countValues: function () {
	  return ExtObj.countValues(this);
	},
	
	
	diff: function () {
	    return ExtObj.diff(this);
	},
	
	
	diffAssoc: function() {
	    return ExtObj.diffAssoc(this);
	},
	
	
	diffKey: function () {
	    return ExtObj.diffKey(this);
	},
	
	
	keyExists: function ( key ) {
	    return ExtObj.keyExists(this, key);
	},
	
	
	keys: function(search_value, strict ) {
	    return ExtObj.keys(this, search, strict);
	},
	
	/**
	 * Pad array to the specified length with a value
	 * @param {Object} pad_size (new array size)
	 * @param {Object} pad_value 
	 * @return {Array}
	 * 	   myArray = [ 7, 8, 9 ];
	 *     example 1: myArray.pad(2, 'a');
	 *     returns 1: [ 7, 8, 9]
	 *     example 2: myArray.pad(5, 'a');
	 *     returns 2: [ 7, 8, 9, 'a', 'a']
	 *     example 3: myArray.pad(5, 2);
	 *     returns 3: [ 7, 8, 9, 2, 2]
	 *     example 4: myArray.pad(-5, 'a');
	 *     returns 4: [ 'a', 'a', 7, 8, 9 ]
	 */
	pad: function ( pad_size, pad_value ) {	
	    var pad = [], newArray = [], newLength, i=0;
	
	    if ( this instanceof Array && !isNaN ( pad_size ) ) {
	        newLength = ( ( pad_size < 0 ) ? ( pad_size * -1 ) : pad_size );
	        if ( newLength > this.length ) {
	            for ( i = 0; i < ( newLength - this.length ); i++ ) { newArray [ i ] = pad_value; }
	            pad = ( ( pad_size < 0 ) ? newArray.concat ( this ) : this.concat ( newArray ) );
	        } else {
	            pad = this;
	        }
	    }
	
	    return pad;
	},
	
	/**
	 * Calculate the product of values in an array
	 * @return int or NaN 
	 * 	   myArray = [ 2, 4, 6, 8 ];
	 *     example 1: myArray.product();
	 *     returns 1: 384
	 */
	product: function () {
	    var Index = 0, Product = 1;
	    if ( this instanceof Array ) {
	        while ( Index < this.length ) {
	            Product *= ( !isNaN ( this [ Index ] ) ? this [ Index ] : 0 );
	            Index++;
	        }
	    } else {
	        Product = null;
	    }
	
	    return Product;
	},
	
	/**
	 * Return an array with elements in reverse order
	 * @param {Bool} preserve_keys
	 * @return {Array}
	 *     example 1: 	myArray = [ 'php', '4.0', ['green', 'red'] ];
	 *     				myArray.reverse(true);
	 *     returns 1: { 2: ['green', 'red'], 1: 4, 0: 'php'}
	 */
	reverse: function (preserve_keys ) {
	    var arr_len=this.length, newkey=0, tmp_ar = {};
	
	    for(var key in this){
	        newkey=arr_len-key-1;
	        tmp_ar[(!!preserve_keys)?newkey:key]=this[newkey];
	    }
	    return tmp_ar;
	},
	
	
	search: function ( needle, strict ) {
	    return ExtObj.search(this, needle, strict);
	},
	
	/**
	 * Calculate the sum of values in an array
	 * @return (int) (NaN)
	 *     example 1: 	myArray = [4, 9, 182.6];
	 *     				myArray.sum();
	 *     returns 1: 195.6
	 */
	sum: function () {
	    var key, sum=0;
	
	    // input sanitation
	    if( !this || (this.constructor !== Array && this.constructor !== Object) || !this.length ){
	        return null;
	    }
	
	    for(var key in this){
	        sum += this[key];
	    }
	    return sum;
	},
	
	unique: function () {
	    return ExtObj.unique(this);
	},
	
	values: function () {
	    return ExtObj.values(this);
	},
	
	end: function () {
	    return ExtObj.end(this);
	},
	
	reset: function () {
	    return ExtObj.reset(this);
	},
	
	walk: function (funcname, userdata) {
	   	return ExtObj.walk(this, funcname, userdata);
	}
	
	
});
/**
 * Extension de l'objet Natif Date
 */
Date.implement ({
	/**
	 * Validate a Gregorian date
	 * @param {Int} month
	 * @param {Int} day
	 * @param {Int} year
	 *     example 1: checkdate(12, 31, 2000);
	 *     returns 1: true
	 *     example 2: checkdate(2, 29, 2001);
	 *     returns 2: false
	 *     example 3: checkdate(03, 31, 2008);
	 *     returns 3: true
	 *     example 4: checkdate(1, 390, 2000);
	 *     returns 4: false
	 */
	checkdate: function ( month, day, year ) {
	   var myDate = new Date();
	    myDate.setFullYear( year, (month - 1), day );
	
	    return ((myDate.getMonth()+1) == month && day<32); 
	},
	
	/**
	 * Format a local time/date
	 * @param {Object} format
	 * @param {Object} timestamp
	 *     example 1: Date.format('H:m:s \\m \\i\\s \\m\\o\\n\\t\\h', 1062402400);
	 *     returns 1: '09:09:40 m is month'
	 *     example 2: Date.format('F j, Y, g:i a', 1062462400);
	 *     returns 2: 'September 2, 2003, 2:26 am'
	 */
	format: function ( formatType, timestamp ) {
	    
	
	    var a, jsdate=((timestamp) ? new Date(timestamp*1000) : new Date());
	    var pad = function(n, c){
	        if( (n = n + "").length < c ) {
	            return new Array(++c - n.length).join("0") + n;
	        } else {
	            return n;
	        }
	    };
	    var txt_weekdays = ["Sunday","Monday","Tuesday","Wednesday",
	        "Thursday","Friday","Saturday"];
	    var txt_ordin = {1:"st",2:"nd",3:"rd",21:"st",22:"nd",23:"rd",31:"st"};
	    var txt_months =  ["", "January", "February", "March", "April",
	        "May", "June", "July", "August", "September", "October", "November",
	        "December"];
	
	    var f = {
	        // Day
	            d: function(){
	                return pad(f.j(), 2);
	            },
	            D: function(){
	                t = f.l(); return t.substr(0,3);
	            },
	            j: function(){
	                return jsdate.getDate();
	            },
	            l: function(){
	                return txt_weekdays[f.w()];
	            },
	            N: function(){
	                return f.w() + 1;
	            },
	            S: function(){
	                return txt_ordin[f.j()] ? txt_ordin[f.j()] : 'th';
	            },
	            w: function(){
	                return jsdate.getDay();
	            },
	            z: function(){
	                return (jsdate - new Date(jsdate.getFullYear() + "/1/1")) / 864e5 >> 0;
	            },
	
	        // Week
	            W: function(){
	                var a = f.z(), b = 364 + f.L() - a;
	                var nd2, nd = (new Date(jsdate.getFullYear() + "/1/1").getDay() || 7) - 1;
	
	                if(b <= 2 && ((jsdate.getDay() || 7) - 1) <= 2 - b){
	                    return 1;
	                } else{
	
	                    if(a <= 2 && nd >= 4 && a >= (6 - nd)){
	                        nd2 = new Date(jsdate.getFullYear() - 1 + "/12/31");
	                        return date("W", Math.round(nd2.getTime()/1000));
	                    } else{
	                        return (1 + (nd <= 3 ? ((a + nd) / 7) : (a - (7 - nd)) / 7) >> 0);
	                    }
	                }
	            },
	
	        // Month
	            F: function(){
	                return txt_months[f.n()];
	            },
	            m: function(){
	                return pad(f.n(), 2);
	            },
	            M: function(){
	                t = f.F(); return t.substr(0,3);
	            },
	            n: function(){
	                return jsdate.getMonth() + 1;
	            },
	            t: function(){
	                var n;
	                if( (n = jsdate.getMonth() + 1) == 2 ){
	                    return 28 + f.L();
	                } else{
	                    if( n & 1 && n < 8 || !(n & 1) && n > 7 ){
	                        return 31;
	                    } else{
	                        return 30;
	                    }
	                }
	            },
	
	        // Year
	            L: function(){
	                var y = f.Y();
	                return (!(y & 3) && (y % 1e2 || !(y % 4e2))) ? 1 : 0;
	            },
	            //o not supported yet
	            Y: function(){
	                return jsdate.getFullYear();
	            },
	            y: function(){
	                return (jsdate.getFullYear() + "").slice(2);
	            },
	
	        // Time
	            a: function(){
	                return jsdate.getHours() > 11 ? "pm" : "am";
	            },
	            A: function(){
	                return f.a().toUpperCase();
	            },
	            B: function(){
	                // peter paul koch:
	                var off = (jsdate.getTimezoneOffset() + 60)*60;
	                var theSeconds = (jsdate.getHours() * 3600) +
	                                 (jsdate.getMinutes() * 60) +
	                                  jsdate.getSeconds() + off;
	                var beat = Math.floor(theSeconds/86.4);
	                if (beat > 1000) beat -= 1000;
	                if (beat < 0) beat += 1000;
	                if ((String(beat)).length == 1) beat = "00"+beat;
	                if ((String(beat)).length == 2) beat = "0"+beat;
	                return beat;
	            },
	            g: function(){
	                return jsdate.getHours() % 12 || 12;
	            },
	            G: function(){
	                return jsdate.getHours();
	            },
	            h: function(){
	                return pad(f.g(), 2);
	            },
	            H: function(){
	                return pad(jsdate.getHours(), 2);
	            },
	            i: function(){
	                return pad(jsdate.getMinutes(), 2);
	            },
	            s: function(){
	                return pad(jsdate.getSeconds(), 2);
	            },
	            //u not supported yet
	
	        // Timezone
	            //e not supported yet
	            //I not supported yet
	            O: function(){
	               var t = pad(Math.abs(jsdate.getTimezoneOffset()/60*100), 4);
	               if (jsdate.getTimezoneOffset() > 0) t = "-" + t; else t = "+" + t;
	               return t;
	            },
	            P: function(){
	                var O = f.O();
	                return (O.substr(0, 3) + ":" + O.substr(3, 2));
	            },
	            //T not supported yet
	            //Z not supported yet
	
	        // Full Date/Time
	            c: function(){
	                return f.Y() + "-" + f.m() + "-" + f.d() + "T" + f.h() + ":" + f.i() + ":" + f.s() + f.P();
	            },
	            //r not supported yet
	            U: function(){
	                return Math.round(jsdate.getTime()/1000);
	            }
	    };
	
	    return formatType.replace(/[\\]?([a-zA-Z])/g, function(t, s){
	        if( t!=s ){
	            // escaped
	            ret = s;
	        } else if( f[s] ){
	            // a date function exists
	            ret = f[s]();
	        } else{
	            // nothing special
	            ret = s;
	        }
	
	        return ret;
	    });
	},
	/**
	 * Get Unix timestamp for a date
	 *     example 1: Date.mktime(14, 10, 2, 2, 1, 2008);
	 *     returns 1: 1201871402
	 *     example 2: Date.mktime(0, 0, 0, 0, 1, 2008);
	 *     returns 2: 1196463600
	 */
	mktime: function () {
	   
	    
	    var no, ma = 0, mb = 0, i = 0, d = new Date(), argv = arguments, argc = argv.length;
	    d.setHours(0,0,0); d.setDate(1); d.setMonth(1); d.setYear(1972);
	 
	    var dateManip = {
	        0: function(tt){ return d.setHours(tt); },
	        1: function(tt){ return d.setMinutes(tt); },
	        2: function(tt){ set = d.setSeconds(tt); mb = d.getDate() - 1; return set; },
	        3: function(tt){ set = d.setMonth(parseInt(tt)-1); ma = d.getFullYear() - 1972; return set; },
	        4: function(tt){ return d.setDate(tt+mb); },
	        5: function(tt){ return d.setYear(tt+ma); }
	    };
	    
	    for( i = 0; i < argc; i++ ){
	        no = parseInt(argv[i]*1);
	        if (isNaN(no)) {
	            return false;
	        } else {
	            // arg is number, let's manipulate date object
	            if(!dateManip[i](no)){
	                // failed
	                return false;
	            }
	        }
	    }
	
	    return Math.floor(d.getTime()/1000);
	},
	
	/**
	 * Format a gap of time
	 * @param {Int} start time in milliseconds
	 * @param {Int} stop time in milliseconds
	 * @param {Boolean} format Optionnal => Output a string formated
	 * @param {Array} typeFormat => If you have selected format, it's the array with times definitions 
	 */
	fTime: function(start, stop, format, typeFormat) {
		DiffSec = Math.floor((stop-start)/1000);
		DiffMin = Math.floor(DiffSec/60);
		Diffheure = Math.floor(DiffMin/60);
		DiffJour = Math.floor(Diffheure/24);
		if (format && typeFormat == null)
			typeFormat = {'d':'d','h':'h','m':'min','s':'sec'};
		while (DiffMin>=60)
			DiffMin = DiffMin-60;
				
		while (Diffheure>=24)
			Diffheure = Diffheure-24;
				
		while (DiffSec>=60)
			DiffSec = DiffSec-60;
		
		if (format === true)
		{
			str = "";
			if (DiffJour != 0)
				str += DiffJour+"j ";
				
			if (DiffJour == 0 && Diffheure == 0) {}
			else 
				str += Diffheure+"h ";
			
			if (DiffMin == 0 && Diffheure == 0) {}
			else 
				str += DiffMin+"min ";
			
			str += DiffSec+"sec";
			return str;
		}
		else 
		 return Array(DiffSec, DiffMin, Diffheure, DiffJour);
	},
	
	/**
	 * Return current Unix timestamp
	 *     example 1: timeStamp = Date.time();
	 *     results 1: timeStamp > 1000000000 && timeStamp < 2000000000
	 */
	time: function () {
	    // 
	    // 
	    // +    discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_time/
	    // +       version: 809.522
	    // +   original by: GeekFG (http://geekfg.blogspot.com)
	    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	    // +   improved by: metjay
	    // 
	    
	    return Math.round(new Date().getTime()/1000);
	}
});

function Display(){}	
/**
 * Retourne la position absolue en ordonnée d'un element
 * @param  (Object) oElement: 		element dont l'on cherche la position en X
 * @return (int)		iReturnValue: position en X
 */
Display.getY = function (oElement){
		var iReturnValue = 0;
	
		while( oElement != null ) {
			iReturnValue += oElement.offsetTop;
			oElement = oElement.offsetParent;
		}
		
		return iReturnValue;
	};
/**
 * Retourne la position absolue en abscisse d'un element
 * @param  (Object) oElement: 		element dont l'on cherche la position en Y
 * @return (int)		iReturnValue: position en Y
 */
Display.getX = function (oElement){
		var iReturnValue = 0;
		
		while( oElement != null ){
			iReturnValue += oElement.offsetLeft;
			oElement = oElement.offsetParent;
		}
		
	return iReturnValue;
	};
/**
 * Fonction permettant d'afficher des interactions SexyBox (plug Mootools)
 * 
 * @param string messageType le type de message
 * @param string messageText le message a afficher
 * @param string idForm l'id du formulaire à submit (optionnel)
 */		
Display.showMessage = function (messageType,messageText,idForm)	{
	sexy = new SexyAlertBox();
	if (messageType == 'info' || messageType == 'success' || messageType == 'warning' || messageType == 'error')
		eval("sexy."+messageType+"(messageText);");
	
	else if (messageType == 'confirm')
	{
		sexy.confirm(messageText,{
			onComplete: function(returnvalue) 
				{
			      if(returnvalue)
			      	document.getElementById(idForm).submit();
			      else
			      	return false;
		    	}
  		});					
	}				
};
/**
 * @author satyre
 */
Element.implement ({
	/**
	 * innerHTML more javascript execution
	 * The script must be into a div with the classname "execJs"
	 * @require Mootools 1.2
	 * @param {Object} html
	 */
	innerDHTML : function (html) {
		this.innerHTML = html;
		els = this.getElements('div.execJs');
		for (i = 0; i < els.length; i++) 
		{
			eval(els[i].get("html"));
			els[i].destroy();
	  }
	}
});
/**
 * Classe File
 * @param {Object} filename
 * @author 58062
 * @from Originals by PHPJS

function File(filename){
	
}
 */
var File = new Class ({
	
	initialize: function(filename) {
		this.filename = filename;
		this.extension = null;
	},
	
	/**
	 * Check File Extension 
	 * @param {Object} extension
	 * @param {Object} file
	 */
	checkExtension: function (extension,file)
	{
		if (file == null && this.filename == null)
			alert("Aucun Fichier donné pour vérification File::checkExtension()");
		else if(file == null)
			word = this.filename;
		else
			word = file;
			
		var lastPos = -1;
	
		// Trouve la derniere position du point
		for (var i = 0; i < word.length; i++) 	
	  	if (word.indexOf(".",i) != -1)
				lastPos = word.indexOf(".", i);  
		
		// Si on a trouve le caractere
		if (lastPos != -1)
		{
			this.extension = word.substr(lastPos+1);
					
			// Si l'extension n'est pas la bonne
			if (extension.toUpperCase() != this.extension.toUpperCase())
				return 0;
			// Sinon c'est good
			else
				return 1;
		}
		else
			return 0;
	},
	
	/**
	 * Return the filename from an entire path
	 * @param {Object} path
	 * @param {Object} suffix
	 *     example 1: basename('/www/site/home.htm', '.htm');
     *     returns 1: 'home'
	 */
	basename: function (path, suffix) {
    // 
		var pathGiven = null;
		if (path != null)
			pathGiven = path;
		else if (this.filename != null)
			pathGiven = this.filename;
		else
			alert("Aucun fichier donné pour File::basename()");
		
		var suf = null;	
		if (suffix != null)
			suf = suffix;
		else if (this.extension != null)
			suf = "."+this.extension;
		else
			alert("Aucun Suffix donné pour File::basename()");
			
		if (suf != null && pathGiven != null) 
		{
			var b = pathGiven.replace(/^.*[\/\\]/g, '');
			if (typeof(suf) == 'string' && b.substr(b.length - suf.length) == suf) {
				b = b.substr(0, b.length - suf.length);
			}
			return b;
		}
	},
	
	/**
	 * Return the dirname
	 * @param {Object} path
	 *     example 1: dirname('/etc/passwd');
     *     returns 1: '/etc'
     *     example 2: dirname('c:/Temp/x');
     *     returns 2: 'c:/Temp'
     *     example 3: dirname('/dir/test/');
     *     returns 3: '/dir'
	 */
	dirname: function(path) {
    	var pathGiven = null
		if (path != null)
			pathGiven = path;
		else if (this.filename != null)
			pathGiven = this.filename;
		else
			alert("Aucun Path donné pour File::dirname()")
    	return path.replace(/\\/g,'/').replace(/\/[^\/]*\/?$/, '');
	},
	
	/**
	 * Calculates the md5 hash of a given file
	 * @param {Object} url
	 * -    depends on: fileGetContents()
	 * -    depends on: String.md5
	 *     example 1: File.md5('http://kevin.vanzonneveld.net/pj_test_supportfile_1.htm');
	 *     returns 1: '202cb962ac59075b964b07152d234b70'
	 */
	md5: function( url ) {
	   return fileGetContents(url).md5();
	},
	
	/**
	 * Calculates the sha1 hash of a given file
	 * @param {Object} url
	 * -    depends on: fileGetContents()
	 * -    depends on: String.sha1
	 *     example 1: File.sha1('http://kevin.vanzonneveld.net/pj_test_supportfile_1.htm');
	 */
	sha1: function( url ) {
	   return fileGetContents(url).sha1();
	},
	
	/**
	 * Format File Size
	 * @param {Object} size
	 * @param {Object} dec
	 * @param {Object} type Types Array[o, ko, mo, go, to, zo];
	 */
	fSize: function(size, dec, type) {
		if(!dec || dec < 0 || dec == null)
			dec = 2;
		if (type == null)
			type = ['o', 'ko', 'mo', 'go', 'to', 'zo'];
		var times = 0;
		var nsize = Number(size);
		var toEval = '';
		while( nsize > 1024 ) {
			nsize = nsize / 1024;
			toEval += ' / 1024';
			times++;
		}
		if( times > 0 )
			eval( 'size = ( size' + toEval + ' );' );
		if(dec > 0) {
			var moltdiv = '(';
			while(dec > 0) {
				moltdiv += '10*';
				dec--;
			}
			moltdiv = moltdiv.substr(0, (moltdiv.length - 1)) + ')';
			eval( 'size = Math.round(size * ' + moltdiv + ') / ' + moltdiv + ';' );
		}
		return size + ' ' + type[times];
	}
	
});	
/**
 * Class Form
 * @param {Object} form Form Element reference
 * Obtain this by the magic Mootools fct : new Form($('id));
 */
var Form = new Class({
	initialize: function(form){
		if (typeof form == "string")
			this.form = $(form);
		else
			this.form = form;
		this.defaultValues = {};
		this.resultBox = null;
		this.resultClasses = {};
		this.specificFct = null;
	},
	
	/**
	 * Permit to submit any form
	 * @param {Object} Form Element reference
	 */
	submit: function(){
		this.form.submit();
	},
	
	/**
	 * Delete and Save the input default value 
	 * @param {Object} el
	 * @param {String} Optionnal specify wich type it should be 
	 */
	fill: function(el){
		this.intervalIe = null;
		
		if (!ExtObj.keyExists(this.defaultValues, el.name)) {
			this.defaultValues[el.name] = {};
			this.defaultValues[el.name]['value'] = el.value;
			if (arguments.length > 1) 
				this.defaultValues[el.name]['type'] = el.type;
				
			
			
		}
		if (this.defaultValues[el.name]['value'] == el.value) {
			el.value = "";
			if (ExtObj.keyExists(this.defaultValues[el.name], 'type'))
				if (Browser.Engine.trident){ 
					var newEl = new Element(el.tagName);
					newEl.type = arguments[1];				
					for (key in el)
					{
						if (key != 'type' && key != 'height' && key != 'width'){						
							try{
								eval("newEl."+key+" = el."+key+";");
							}
							catch(e){
							 // Because Ms Developers have smoke weed during development, Fucking properties can't be set !!  
							}
							
						}
					}
					newEl.replaces(el);
					alert(this.form[newEl.name]);
					newEl.focus();
					alert(this.form[newEl.name]);
					//this.intervalIe=setInterval(this.checkInject(), 500, newEl.name);
				}
				else
					el.setProperty('type', arguments[1]);
		}
				
	},
	
	checkInject: function(elementName)
	{	alert("Timer");
		if (this.form.elements[elementName] != null){
				clearInterval(this.intervalIe);
				this.form.elements[elementName].focus();
		}
	},
	
	/**
	 * Restore the input default value
	 * @param {Object} el
	 */
	restore: function(el){
		var finalEl = el;
		if (this.defaultValues[el.name]['value'] == "undefined")
			return Note.error('No Formq::fill() function attributed to this input<br />Error in Form::restore()');
		if (el.value == '') {
			if (ExtObj.keyExists(this.defaultValues[el.name], 'type')) 
			{
				if (Browser.Engine.trident){ 
					var newEl = new Element(el.tagName);
					newEl.type = this.defaultValues[el.name]['type'];				
					for (key in el)
					{
						if (key != 'type' && key != 'height' && key != 'width'){						
							try{
								eval("newEl."+key+" = el."+key+";");
							}
							catch(e){
							 // Because Ms Developers have smoke weed during development, Fucking properties can't be set !! 
							}
							
						}
					}
					newEl.replaces(el);
					finalEl = newEl;
				}
				else
					el.setProperty('type', this.defaultValues[el.name]['type']);
					
			}
			finalEl.value = this.defaultValues[el.name]['value'];
		}
	},
	
	/**
	 * Add a listener on a Key
	 * @param {Int} keyCode
	 * @param {String} userFunction
	 */
	setKey: function(keyCode, userFunction){
		this.form.addEvent('keydown', function(e){
			if (window.event) {
				if (window.event.keyCode == keyCode)
				{
					eval(userFunction);
					e.stop();
				}
			}
			else if (e)
				if (e.code == keyCode)
				{
					eval(userFunction);
					e.stop();
				}
			
		});
	},
	
	/**
	 * Set the box to show all the form Results (Success and errors)
	 * @param {Object} item
	 */
	setResultBox: function(item){
		if (typeof item == "string")
			item = $(item);
		this.resultBox = item;
			
	},
	/**
	 * Set the classes which been called for the form box result
	 * @param {String} error
	 * @param {string} success
	 */
	setResultClasses: function(error, success){
		this.resultClasses['error'] = error;
		this.resultClasses['success'] = success;
	},
	
	/**
	 * Display a result message for the current form
	 * @param {String} str
	 * @param {String} type [error||success]
	 */
	displayGlobalMsg: function(str, type){
		if (type != "error" && type != "success")
			return Note.warning('The argument type should be \'<b>error</b>\' or \'<b>success</b>\' for the function Form::displayGlobalMsg()<br />Warning in the form <b>'+this.form.get('id')+'</b>');
		if (!ExtObj.keyExists(this.resultClasses, 'error') || !ExtObj.keyExists(this.resultClasses, 'success'))
			return Note.error('You must set results classes for the form <b>'+this.form.get('id')+'</b> to execute Form::displayGlobalMsg()<br />resultClasses[\'error\']: <b>'+this.resultClasses['error']+'</b><br />resultClasses[\'success\']: <b>'+this.resultClasses['success']+'</b>');
		if (this.resultBox == null)
			return Note.error('You must set results box for the form <b>'+this.form.get('id')+'</b> to execute Form::displayGlobalMsg()');
		this.resultBox.set('class', this.resultClasses[type]);
		this.resultBox.set('html', str);
		return;			
	},
	
	/**
	 * Reset the Form box result
	 */
	resetGlobalMsg: function(){
		this.displayGlobalMsg('', 'success');
		this.resultBox.set('class', '');
		return;
	},
	/**
	 * Return an form element object
	 * @param {String} name
	 */
	get: function(name){
		if (this.form[name] == "undefined")
			return Note.error('The name \''+name+'\' doesn\'t exist in the Form '+this.form.get('id')+'<br />Error in Form::get()');
		var el = $$('#'+this.form.get('id')+' [name='+name+']');
		if (el.length == 1)
			return el[0];
		return el;
	},
	
	/**
	 * Return an input's label by the input name
	 * @param {String} name
	 */
	getLabel: function(name){
		if (this.form[name] == "undefined")
			return Note.error('The name \''+name+'\' doesn\'t exist in the Form '+this.form.get('id')+'<br />Error in Form::getLabel()');
		var idinput = this.form[name].get("id");
		if (!$chk(this.form.getElement('label[for='+idInput+']')))
			return Note.error('The label for the name: \''+name+'\' doesn\'t exist in the Form '+this.form.get('id')+'<br />Error in Form::getLabel()');
		return this.form.getElement('label[for='+idInput+']');
	},
	
	/**
	 * Return value of form element
	 * @param {String} name
	 */
	getValue: function(name){
		if (this.form[name] == "undefined")
			return Note.error('The name \''+name+'\' doesn\'t exist in the Form '+this.form.get('id')+'<br />Error in Form::getValue()');
		return this.get(name).value;
	}
	
	
});
/**
 * Extension de l'objet String
 */
String.implement({
	
	/**
	 * Check if the String is correct E-mail adress
	 * @return (Boolean)
	 */
	isEmail: function () {
		var verif = /^[a-zA-Z0-9]([-_.]?[0-9a-zA-Z])+@[a-zA-Z0-9-]{2,}[.][a-zA-Z]{2,3}$/
		if (verif.exec(this) == null)
			return false;
		else
			return true;
	},
	
	/**
	 * Replace & by &Amp; 
	 * Use it in get Ajax Request
	 */
	encodeAmp: function () {
		return (this.replace("&", ";Amp;"));
	},
	
	/**
	 * Transform first char of each word in a string to uppercase
	 */
	ucwords: function () {
		return this.replace(/^(.)|\s(.)/g, function ( $1 ) { return $1.toUpperCase ( ); } );
	},
	
	/**
	 * Strip whitespace (or other characters) from the beginning and end of a string
	 */
	trim: function () {    
	  return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
	},

	ltrim: function(chars) {
	    chars = chars || "\\s";
	    return this.replace(new RegExp("^[" + chars + "]+", "g"), "");
	},

	rtrim: function(chars) {
	    chars = chars || "\\s";
	    return this.replace(new RegExp("[" + chars + "]+$", "g"), "");
	},
	
	/**
	 * Check if the String is correct URL
	 */
	isUrl: function () {
		string = this;
		if (this.substr(0, 7) != "http://" && this.substr(0, 8) != "https://")
				string = "http://"+this;
		var RegExp = /^(([\w]+:)?\/\/)?(([\d\w]|%[a-fA-f\d]{2,2})+(:([\d\w]|%[a-fA-f\d]{2,2})+)?@)?([\d\w][-\d\w]{0,253}[\d\w]\.)+[\w]{2,4}(:[\d]+)?(\/([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)*(\?(&?([-+_~.\d\w]|%[a-fA-f\d]{2,2})=?)*)?(#([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)?$/;
	  if(RegExp.test(string))
	    return true;
	  else
	  	return false;
	},
	
	/**
	 * Quote regular expression characters
	 */
	preg_quote: function() {
	   return this.replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
	},
	
	/**
	 * Quote string with slashes
	 */
	addslashes: function (  ) {
   		return (this+'').replace(/([\\"'])/g, "\\$1").replace(/\0/g, "\\0");   
	},
	
	/**
	 * Convert binary data into hexadecimal representation
	 */
	bin2hex: function (){
		var i, f = this.length, a = [];
		for(i = 0; i<f; i++)
			a[i] = this.charCodeAt(i).toString(16);
		
		return a.join('');
	},
	
	/**
	 * Split a string by string
	 * @param {Object} delimiter
	 * @param {Object} limit
	 */
	explode: function (delimiter, limit ) {
	    var emptyArray = { 0: '' };
	    
	    // third argument is not required
	    if (arguments.length < 1 || typeof arguments[0] == 'undefined') 
			return Note.error('You missed to specify the delimiter for the String.explode()<br />String Value: <b>'+this+'</b>');
			
	 
	    if ( delimiter === '' || typeof delimiter == 'boolean' || delimiter === null )
	        return Note.error('You missed to specify the delimiter for the String.explode()<br />String Value: <b>'+this+'</b>');
	    
	 
	    if ( typeof delimiter == 'function' || typeof delimiter == 'object')
	        return Note.warning('Delimiter specified in String.explode() is an object or a function. It should be a string<br />String Value: <b>'+this+'</b>');
	    
	 
	    if ( delimiter === true ) {
	        delimiter = '1';
	    }
	    
	    if (!limit) {
	        return this.toString().split(delimiter.toString());
	    } else {
	        // support for limit argument
	        var splitted = this.toString().split(delimiter.toString());
	        var partA = splitted.splice(0, limit - 1);
	        var partB = splitted.join(delimiter.toString());
	        partA.push(partB);
	        return partA;
	    }
	},
	
	/**
	 * Calculate the md5 hash of a string
	 * @return MD5 String
	 * depends on: String.utf8Encode
	 *     example 1: 	str = 'Kevin van Zonneveld';
	 *     				str.md5();
	 *     returns 1: '6e658d4bfcb59cc13f96c14450ac40b9'
	 */
	md5: function () {
	    var RotateLeft = function(lValue, iShiftBits) {
	            return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits));
	        };
	
	    var AddUnsigned = function(lX,lY) {
	            var lX4,lY4,lX8,lY8,lResult;
	            lX8 = (lX & 0x80000000);
	            lY8 = (lY & 0x80000000);
	            lX4 = (lX & 0x40000000);
	            lY4 = (lY & 0x40000000);
	            lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);
	            if (lX4 & lY4) {
	                return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
	            }
	            if (lX4 | lY4) {
	                if (lResult & 0x40000000) {
	                    return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
	                } else {
	                    return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
	                }
	            } else {
	                return (lResult ^ lX8 ^ lY8);
	            }
	        };
	
	    var F = function(x,y,z) { return (x & y) | ((~x) & z); };
	    var G = function(x,y,z) { return (x & z) | (y & (~z)); };
	    var H = function(x,y,z) { return (x ^ y ^ z); };
	    var I = function(x,y,z) { return (y ^ (x | (~z))); };
	
	    var FF = function(a,b,c,d,x,s,ac) {
	            a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
	            return AddUnsigned(RotateLeft(a, s), b);
	        };
	
	    var GG = function(a,b,c,d,x,s,ac) {
	            a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
	            return AddUnsigned(RotateLeft(a, s), b);
	        };
	
	    var HH = function(a,b,c,d,x,s,ac) {
	            a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
	            return AddUnsigned(RotateLeft(a, s), b);
	        };
	
	    var II = function(a,b,c,d,x,s,ac) {
	            a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
	            return AddUnsigned(RotateLeft(a, s), b);
	        };
	
	    var ConvertToWordArray = function(str) {
	            var lWordCount;
	            var lMessageLength = str.length;
	            var lNumberOfWords_temp1=lMessageLength + 8;
	            var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64;
	            var lNumberOfWords = (lNumberOfWords_temp2+1)*16;
	            var lWordArray=Array(lNumberOfWords-1);
	            var lBytePosition = 0;
	            var lByteCount = 0;
	            while ( lByteCount < lMessageLength ) {
	                lWordCount = (lByteCount-(lByteCount % 4))/4;
	                lBytePosition = (lByteCount % 4)*8;
	                lWordArray[lWordCount] = (lWordArray[lWordCount] | (str.charCodeAt(lByteCount)<<lBytePosition));
	                lByteCount++;
	            }
	            lWordCount = (lByteCount-(lByteCount % 4))/4;
	            lBytePosition = (lByteCount % 4)*8;
	            lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition);
	            lWordArray[lNumberOfWords-2] = lMessageLength<<3;
	            lWordArray[lNumberOfWords-1] = lMessageLength>>>29;
	            return lWordArray;
	        };
	
	    var WordToHex = function(lValue) {
	            var WordToHexValue="",WordToHexValue_temp="",lByte,lCount;
	            for (lCount = 0;lCount<=3;lCount++) {
	                lByte = (lValue>>>(lCount*8)) & 255;
	                WordToHexValue_temp = "0" + lByte.toString(16);
	                WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2);
	            }
	            return WordToHexValue;
	        };
	
	    var x=Array();
	    var k,AA,BB,CC,DD,a,b,c,d;
	    var S11=7, S12=12, S13=17, S14=22;
	    var S21=5, S22=9 , S23=14, S24=20;
	    var S31=4, S32=11, S33=16, S34=23;
	    var S41=6, S42=10, S43=15, S44=21;
	
	    str = this.utf8Encode();
	    x = ConvertToWordArray(str);
	    a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
	
	    for (k=0;k<x.length;k+=16) {
	        AA=a; BB=b; CC=c; DD=d;
	        a=FF(a,b,c,d,x[k+0], S11,0xD76AA478);
	        d=FF(d,a,b,c,x[k+1], S12,0xE8C7B756);
	        c=FF(c,d,a,b,x[k+2], S13,0x242070DB);
	        b=FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);
	        a=FF(a,b,c,d,x[k+4], S11,0xF57C0FAF);
	        d=FF(d,a,b,c,x[k+5], S12,0x4787C62A);
	        c=FF(c,d,a,b,x[k+6], S13,0xA8304613);
	        b=FF(b,c,d,a,x[k+7], S14,0xFD469501);
	        a=FF(a,b,c,d,x[k+8], S11,0x698098D8);
	        d=FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);
	        c=FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);
	        b=FF(b,c,d,a,x[k+11],S14,0x895CD7BE);
	        a=FF(a,b,c,d,x[k+12],S11,0x6B901122);
	        d=FF(d,a,b,c,x[k+13],S12,0xFD987193);
	        c=FF(c,d,a,b,x[k+14],S13,0xA679438E);
	        b=FF(b,c,d,a,x[k+15],S14,0x49B40821);
	        a=GG(a,b,c,d,x[k+1], S21,0xF61E2562);
	        d=GG(d,a,b,c,x[k+6], S22,0xC040B340);
	        c=GG(c,d,a,b,x[k+11],S23,0x265E5A51);
	        b=GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);
	        a=GG(a,b,c,d,x[k+5], S21,0xD62F105D);
	        d=GG(d,a,b,c,x[k+10],S22,0x2441453);
	        c=GG(c,d,a,b,x[k+15],S23,0xD8A1E681);
	        b=GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);
	        a=GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);
	        d=GG(d,a,b,c,x[k+14],S22,0xC33707D6);
	        c=GG(c,d,a,b,x[k+3], S23,0xF4D50D87);
	        b=GG(b,c,d,a,x[k+8], S24,0x455A14ED);
	        a=GG(a,b,c,d,x[k+13],S21,0xA9E3E905);
	        d=GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);
	        c=GG(c,d,a,b,x[k+7], S23,0x676F02D9);
	        b=GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);
	        a=HH(a,b,c,d,x[k+5], S31,0xFFFA3942);
	        d=HH(d,a,b,c,x[k+8], S32,0x8771F681);
	        c=HH(c,d,a,b,x[k+11],S33,0x6D9D6122);
	        b=HH(b,c,d,a,x[k+14],S34,0xFDE5380C);
	        a=HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);
	        d=HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);
	        c=HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);
	        b=HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);
	        a=HH(a,b,c,d,x[k+13],S31,0x289B7EC6);
	        d=HH(d,a,b,c,x[k+0], S32,0xEAA127FA);
	        c=HH(c,d,a,b,x[k+3], S33,0xD4EF3085);
	        b=HH(b,c,d,a,x[k+6], S34,0x4881D05);
	        a=HH(a,b,c,d,x[k+9], S31,0xD9D4D039);
	        d=HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);
	        c=HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);
	        b=HH(b,c,d,a,x[k+2], S34,0xC4AC5665);
	        a=II(a,b,c,d,x[k+0], S41,0xF4292244);
	        d=II(d,a,b,c,x[k+7], S42,0x432AFF97);
	        c=II(c,d,a,b,x[k+14],S43,0xAB9423A7);
	        b=II(b,c,d,a,x[k+5], S44,0xFC93A039);
	        a=II(a,b,c,d,x[k+12],S41,0x655B59C3);
	        d=II(d,a,b,c,x[k+3], S42,0x8F0CCC92);
	        c=II(c,d,a,b,x[k+10],S43,0xFFEFF47D);
	        b=II(b,c,d,a,x[k+1], S44,0x85845DD1);
	        a=II(a,b,c,d,x[k+8], S41,0x6FA87E4F);
	        d=II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);
	        c=II(c,d,a,b,x[k+6], S43,0xA3014314);
	        b=II(b,c,d,a,x[k+13],S44,0x4E0811A1);
	        a=II(a,b,c,d,x[k+4], S41,0xF7537E82);
	        d=II(d,a,b,c,x[k+11],S42,0xBD3AF235);
	        c=II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);
	        b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
	        a=AddUnsigned(a,AA);
	        b=AddUnsigned(b,BB);
	        c=AddUnsigned(c,CC);
	        d=AddUnsigned(d,DD);
	    }
	
	    var temp = WordToHex(a)+WordToHex(b)+WordToHex(c)+WordToHex(d);
	
	    return temp.toLowerCase();
	},
	
	/**
	 * Encodes an ISO-8859-1 string to UTF-8
	 * @return UTF-8 encoded String
	 */
	utf8Encode: function  () {
	    string = this.replace(/\r\n/g,"\n");
	    var utftext = "";
	    var start, end;
	 
	    start = end = 0;
	    for (var n = 0; n < string.length; n++) {
	        var c = string.charCodeAt(n);
	        var enc = null;
	 
	        if (c < 128) {
	            end++;
	        } else if((c > 127) && (c < 2048)) {
	            enc = String.fromCharCode((c >> 6) | 192) + String.fromCharCode((c & 63) | 128);
	        } else {
	            enc = String.fromCharCode((c >> 12) | 224) + String.fromCharCode(((c >> 6) & 63) | 128) + String.fromCharCode((c & 63) | 128);
	        }
	        if (enc != null) {
	            if (end > start) {
	                utftext += string.substring(start, end);
	            }
	            utftext += enc;
	            start = end = n+1;
	        }
	    }
	    
	    if (end > start) {
	        utftext += string.substring(start, string.length);
	    }
	 
	    return utftext;
	},
	
	/**
	 * Convert all applicable characters to HTML entities
	 * @return String
	 */
	htmlEntities: function ( ){
	    var histogram = {}, code = 0, tmp_arr = [], i = 0;
	    
	    histogram['34'] = 'quot';
	    histogram['38'] = 'amp';
	    histogram['60'] = 'lt';
	    histogram['62'] = 'gt';
	    histogram['160'] = 'nbsp';
	    histogram['161'] = 'iexcl';
	    histogram['162'] = 'cent';
	    histogram['163'] = 'pound';
	    histogram['164'] = 'curren';
	    histogram['165'] = 'yen';
	    histogram['166'] = 'brvbar';
	    histogram['167'] = 'sect';
	    histogram['168'] = 'uml';
	    histogram['169'] = 'copy';
	    histogram['170'] = 'ordf';
	    histogram['171'] = 'laquo';
	    histogram['172'] = 'not';
	    histogram['173'] = 'shy';
	    histogram['174'] = 'reg';
	    histogram['175'] = 'macr';
	    histogram['176'] = 'deg';
	    histogram['177'] = 'plusmn';
	    histogram['178'] = 'sup2';
	    histogram['179'] = 'sup3';
	    histogram['180'] = 'acute';
	    histogram['181'] = 'micro';
	    histogram['182'] = 'para';
	    histogram['183'] = 'middot';
	    histogram['184'] = 'cedil';
	    histogram['185'] = 'sup1';
	    histogram['186'] = 'ordm';
	    histogram['187'] = 'raquo';
	    histogram['188'] = 'frac14';
	    histogram['189'] = 'frac12';
	    histogram['190'] = 'frac34';
	    histogram['191'] = 'iquest';
	    histogram['192'] = 'Agrave';
	    histogram['193'] = 'Aacute';
	    histogram['194'] = 'Acirc';
	    histogram['195'] = 'Atilde';
	    histogram['196'] = 'Auml';
	    histogram['197'] = 'Aring';
	    histogram['198'] = 'AElig';
	    histogram['199'] = 'Ccedil';
	    histogram['200'] = 'Egrave';
	    histogram['201'] = 'Eacute';
	    histogram['202'] = 'Ecirc';
	    histogram['203'] = 'Euml';
	    histogram['204'] = 'Igrave';
	    histogram['205'] = 'Iacute';
	    histogram['206'] = 'Icirc';
	    histogram['207'] = 'Iuml';
	    histogram['208'] = 'ETH';
	    histogram['209'] = 'Ntilde';
	    histogram['210'] = 'Ograve';
	    histogram['211'] = 'Oacute';
	    histogram['212'] = 'Ocirc';
	    histogram['213'] = 'Otilde';
	    histogram['214'] = 'Ouml';
	    histogram['215'] = 'times';
	    histogram['216'] = 'Oslash';
	    histogram['217'] = 'Ugrave';
	    histogram['218'] = 'Uacute';
	    histogram['219'] = 'Ucirc';
	    histogram['220'] = 'Uuml';
	    histogram['221'] = 'Yacute';
	    histogram['222'] = 'THORN';
	    histogram['223'] = 'szlig';
	    histogram['224'] = 'agrave';
	    histogram['225'] = 'aacute';
	    histogram['226'] = 'acirc';
	    histogram['227'] = 'atilde';
	    histogram['228'] = 'auml';
	    histogram['229'] = 'aring';
	    histogram['230'] = 'aelig';
	    histogram['231'] = 'ccedil';
	    histogram['232'] = 'egrave';
	    histogram['233'] = 'eacute';
	    histogram['234'] = 'ecirc';
	    histogram['235'] = 'euml';
	    histogram['236'] = 'igrave';
	    histogram['237'] = 'iacute';
	    histogram['238'] = 'icirc';
	    histogram['239'] = 'iuml';
	    histogram['240'] = 'eth';
	    histogram['241'] = 'ntilde';
	    histogram['242'] = 'ograve';
	    histogram['243'] = 'oacute';
	    histogram['244'] = 'ocirc';
	    histogram['245'] = 'otilde';
	    histogram['246'] = 'ouml';
	    histogram['247'] = 'divide';
	    histogram['248'] = 'oslash';
	    histogram['249'] = 'ugrave';
	    histogram['250'] = 'uacute';
	    histogram['251'] = 'ucirc';
	    histogram['252'] = 'uuml';
	    histogram['253'] = 'yacute';
	    histogram['254'] = 'thorn';
	    histogram['255'] = 'yuml';
	    
	    for (i = 0; i < this.length; ++i) {
	        code = this.charCodeAt(i);
	        if (code in histogram) {
	            tmp_arr[i] = '&'+histogram[code]+';';
	        } else {
	            tmp_arr[i] = this.charAt(i);
	        }
	    }
	    
	    return tmp_arr.join('');
	},
	
	/**
	 * Convert all HTML entities to their applicable characters
	 * 
	 */
	htmlEntityDecode: function () {
		    var histogram = {}, histogram_r = {}, code = 0;
		    var entity = chr = '';
		    
		    histogram['34'] = 'quot';
		    histogram['38'] = 'amp';
		    histogram['60'] = 'lt';
		    histogram['62'] = 'gt';
		    histogram['160'] = 'nbsp';
		    histogram['161'] = 'iexcl';
		    histogram['162'] = 'cent';
		    histogram['163'] = 'pound';
		    histogram['164'] = 'curren';
		    histogram['165'] = 'yen';
		    histogram['166'] = 'brvbar';
		    histogram['167'] = 'sect';
		    histogram['168'] = 'uml';
		    histogram['169'] = 'copy';
		    histogram['170'] = 'ordf';
		    histogram['171'] = 'laquo';
		    histogram['172'] = 'not';
		    histogram['173'] = 'shy';
		    histogram['174'] = 'reg';
		    histogram['175'] = 'macr';
		    histogram['176'] = 'deg';
		    histogram['177'] = 'plusmn';
		    histogram['178'] = 'sup2';
		    histogram['179'] = 'sup3';
		    histogram['180'] = 'acute';
		    histogram['181'] = 'micro';
		    histogram['182'] = 'para';
		    histogram['183'] = 'middot';
		    histogram['184'] = 'cedil';
		    histogram['185'] = 'sup1';
		    histogram['186'] = 'ordm';
		    histogram['187'] = 'raquo';
		    histogram['188'] = 'frac14';
		    histogram['189'] = 'frac12';
		    histogram['190'] = 'frac34';
		    histogram['191'] = 'iquest';
		    histogram['192'] = 'Agrave';
		    histogram['193'] = 'Aacute';
		    histogram['194'] = 'Acirc';
		    histogram['195'] = 'Atilde';
		    histogram['196'] = 'Auml';
		    histogram['197'] = 'Aring';
		    histogram['198'] = 'AElig';
		    histogram['199'] = 'Ccedil';
		    histogram['200'] = 'Egrave';
		    histogram['201'] = 'Eacute';
		    histogram['202'] = 'Ecirc';
		    histogram['203'] = 'Euml';
		    histogram['204'] = 'Igrave';
		    histogram['205'] = 'Iacute';
		    histogram['206'] = 'Icirc';
		    histogram['207'] = 'Iuml';
		    histogram['208'] = 'ETH';
		    histogram['209'] = 'Ntilde';
		    histogram['210'] = 'Ograve';
		    histogram['211'] = 'Oacute';
		    histogram['212'] = 'Ocirc';
		    histogram['213'] = 'Otilde';
		    histogram['214'] = 'Ouml';
		    histogram['215'] = 'times';
		    histogram['216'] = 'Oslash';
		    histogram['217'] = 'Ugrave';
		    histogram['218'] = 'Uacute';
		    histogram['219'] = 'Ucirc';
		    histogram['220'] = 'Uuml';
		    histogram['221'] = 'Yacute';
		    histogram['222'] = 'THORN';
		    histogram['223'] = 'szlig';
		    histogram['224'] = 'agrave';
		    histogram['225'] = 'aacute';
		    histogram['226'] = 'acirc';
		    histogram['227'] = 'atilde';
		    histogram['228'] = 'auml';
		    histogram['229'] = 'aring';
		    histogram['230'] = 'aelig';
		    histogram['231'] = 'ccedil';
		    histogram['232'] = 'egrave';
		    histogram['233'] = 'eacute';
		    histogram['234'] = 'ecirc';
		    histogram['235'] = 'euml';
		    histogram['236'] = 'igrave';
		    histogram['237'] = 'iacute';
		    histogram['238'] = 'icirc';
		    histogram['239'] = 'iuml';
		    histogram['240'] = 'eth';
		    histogram['241'] = 'ntilde';
		    histogram['242'] = 'ograve';
		    histogram['243'] = 'oacute';
		    histogram['244'] = 'ocirc';
		    histogram['245'] = 'otilde';
		    histogram['246'] = 'ouml';
		    histogram['247'] = 'divide';
		    histogram['248'] = 'oslash';
		    histogram['249'] = 'ugrave';
		    histogram['250'] = 'uacute';
		    histogram['251'] = 'ucirc';
		    histogram['252'] = 'uuml';
		    histogram['253'] = 'yacute';
		    histogram['254'] = 'thorn';
		    histogram['255'] = 'yuml';
		    
		    // Reverse table. Cause for maintainability purposes, the histogram is 
		    // identical to the one in htmlentities.
		    for (code in histogram) {
		        entity = histogram[code];
		        histogram_r[entity] = code; 
		    }
		    
		    return this.replace(/(\&([a-zA-Z]+)\;)/g, function(full, m1, m2){
		        if (m2 in histogram_r) {
		            return String.fromCharCode(histogram_r[m2]);
		        } else {
		            return m2;
		        }
		    });    
	},
	
	/**
	 * Convert special characters to HTML entities
	 * @param {Object} quote_style ENT_QUOTES|ENT_COMPAT|ENT_NOQUOTES|default
	 */
	htmlSpecialChars: function ( quote_style) {
	    string = this.toString();
	    
	    // Always encode
	    string = string.replace(/&/g, '&amp;');
	    string = string.replace(/</g, '&lt;');
	    string = string.replace(/>/g, '&gt;');
	    
	    // Encode depending on quote_style
	    if (quote_style == 'ENT_QUOTES') {
	        string = string.replace(/"/g, '&quot;');
	        string = string.replace(/'/g, '&#039;');
	    } else if (quote_style != 'ENT_NOQUOTES') {
	        // All other cases (ENT_COMPAT, default, but not ENT_NOQUOTES)
	        string = string.replace(/"/g, '&quot;');
	    }
	    
	    return string;
	},

	/**
	 * Convert special HTML entities back to characters
	 * @param {Object} quote_style ENT_QUOTES|ENT_COMPAT|ENT_NOQUOTES|default
	 */
	htmlSpecialCharsDecode: function ( quote_style) {
	    string = this.toString();
	    
	    // Always encode
	    string = string.replace('/&amp;/g', '&');
	    string = string.replace('/&lt;/g', '<');
	    string = string.replace(/&gt;/g, '>');
	    
	    // Encode depending on quote_style
	    if (quote_style == 'ENT_QUOTES') {
	        string = string.replace('/&quot;/g', '"');
	        string = string.replace('/&#039;/g', '\'');
	    } else if (quote_style != 'ENT_NOQUOTES') {
	        // All other cases (ENT_COMPAT, default, but not ENT_NOQUOTES)
	        string = string.replace('/&quot;/g', '"');
	    }
	    
	    return string;
	},
	
	/**
	 * Calculate Levenshtein distance between two strings
	 *     example 1: 	str = 'Kevin van Zonneveld';
	 *     				str.levenshtein('Kevin van Sommeveld');
	 *     returns 1: 3
	 * @param {Object} str2
	 */
	levenshtein: function ( str2 ) {
	    var s, l = (s = this.split("")).length, t = (str2 = str2.split("")).length, i, j, m, n;
	    if(!(l || t)) return Math.max(l, t);
	    for(var a = [], i = l + 1; i; a[--i] = [i]);
	    for(i = t + 1; a[0][--i] = i;);
	    for(i = -1, m = s.length; ++i < m;){
	        for(j = -1, n = str2.length; ++j < n;){
	            a[(i *= 1) + 1][(j *= 1) + 1] = Math.min(a[i][j + 1] + 1, a[i + 1][j] + 1, a[i][j] + (s[i] != str2[j]));
	        }
	    }
	    return a[l][t];
	},
	
	/**
	 * Inserts HTML line breaks before all newlines in a string
	 */
	nl2br: function (  ) {
	    return this.replace(/([^>])\n/g, '$1<br />\n');
	},

	/**
	 * Return ASCII value of character
	 *     example 1: ord('K');
	 *     returns 1: 75
	 */
	ord: function () {
	   return this.charCodeAt(0);
	},

	/**
	 * Parses the string into variables
	 * @param {Object} array
	 *     example 1: 	str = 'first=foo&second=bar';
	 *     				str.parse();
	 *     returns 1: { first: 'foo', second: 'bar' }
	 *     example 2: 	str = 'str_a=Jack+and+Jill+didn%27t+see+the+well.';
	 *     				str.parse();
	 *     returns 2: { str_a: "Jack and Jill didn't see the well." }
	 */
	parse: function ( array){
	    var glue1 = '=';
	    var glue2 = '&';
	
	    var array2 = this.split(glue2);
	    var array3 = [];
	    for(var x=0; x<array2.length; x++){
	        var tmp = array2[x].split(glue1);
	        array3[unescape(tmp[0])] = unescape(tmp[1]).replace(/[+]/g, ' ');
	    }
	
	    if(array){
	        array = array3;
	    } else{
	        return array3;
	    }
	},
	
	/**
	 * Calculate the sha1 hash of a string
	 * -    depends on: utf8Encode
	 *     example 1: 	str = 'Kevin van Zonneveld';
	 *     				str.sha1();
	 *     returns 1: '54916d2e62f65b3afa6e192e6a601cdbe5cb5897'
	 */
	sha1: function  () {
	    var rotate_left = function(n,s) {
	            var t4 = ( n<<s ) | (n>>>(32-s));
	            return t4;
	        };
	
	    var lsb_hex = function(val) {
	            var str="";
	            var i;
	            var vh;
	            var vl;
	
	            for( i=0; i<=6; i+=2 ) {
	                vh = (val>>>(i*4+4))&0x0f;
	                vl = (val>>>(i*4))&0x0f;
	                str += vh.toString(16) + vl.toString(16);
	            }
	            return str;
	        };
	
	    var cvt_hex = function(val) {
	            var str="";
	            var i;
	            var v;
	
	            for( i=7; i>=0; i-- ) {
	                v = (val>>>(i*4))&0x0f;
	                str += v.toString(16);
	            }
	            return str;
	        };
	
	    var blockstart;
	    var i, j;
	    var W = new Array(80);
	    var H0 = 0x67452301;
	    var H1 = 0xEFCDAB89;
	    var H2 = 0x98BADCFE;
	    var H3 = 0x10325476;
	    var H4 = 0xC3D2E1F0;
	    var A, B, C, D, E;
	    var temp;
	
	    str = this.utf8Encode();
	    var str_len = str.length;
	
	    var word_array = new Array();
	    for( i=0; i<str_len-3; i+=4 ) {
	        j = str.charCodeAt(i)<<24 | str.charCodeAt(i+1)<<16 |
	        str.charCodeAt(i+2)<<8 | str.charCodeAt(i+3);
	        word_array.push( j );
	    }
	
	    switch( str_len % 4 ) {
	        case 0:
	            i = 0x080000000;
	        break;
	        case 1:
	            i = str.charCodeAt(str_len-1)<<24 | 0x0800000;
	        break;
	        case 2:
	            i = str.charCodeAt(str_len-2)<<24 | str.charCodeAt(str_len-1)<<16 | 0x08000;
	        break;
	        case 3:
	            i = str.charCodeAt(str_len-3)<<24 | str.charCodeAt(str_len-2)<<16 | str.charCodeAt(str_len-1)<<8    | 0x80;
	        break;
	    }
	
	    word_array.push( i );
	
	    while( (word_array.length % 16) != 14 ) word_array.push( 0 );
	
	    word_array.push( str_len>>>29 );
	    word_array.push( (str_len<<3)&0x0ffffffff );
	
	    for ( blockstart=0; blockstart<word_array.length; blockstart+=16 ) {
	        for( i=0; i<16; i++ ) W[i] = word_array[blockstart+i];
	        for( i=16; i<=79; i++ ) W[i] = rotate_left(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
	
	        A = H0;
	        B = H1;
	        C = H2;
	        D = H3;
	        E = H4;
	
	        for( i= 0; i<=19; i++ ) {
	            temp = (rotate_left(A,5) + ((B&C) | (~B&D)) + E + W[i] + 0x5A827999) & 0x0ffffffff;
	            E = D;
	            D = C;
	            C = rotate_left(B,30);
	            B = A;
	            A = temp;
	        }
	
	        for( i=20; i<=39; i++ ) {
	            temp = (rotate_left(A,5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff;
	            E = D;
	            D = C;
	            C = rotate_left(B,30);
	            B = A;
	            A = temp;
	        }
	
	        for( i=40; i<=59; i++ ) {
	            temp = (rotate_left(A,5) + ((B&C) | (B&D) | (C&D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff;
	            E = D;
	            D = C;
	            C = rotate_left(B,30);
	            B = A;
	            A = temp;
	        }
	
	        for( i=60; i<=79; i++ ) {
	            temp = (rotate_left(A,5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff;
	            E = D;
	            D = C;
	            C = rotate_left(B,30);
	            B = A;
	            A = temp;
	        }
	
	        H0 = (H0 + A) & 0x0ffffffff;
	        H1 = (H1 + B) & 0x0ffffffff;
	        H2 = (H2 + C) & 0x0ffffffff;
	        H3 = (H3 + D) & 0x0ffffffff;
	        H4 = (H4 + E) & 0x0ffffffff;
	    }
	
	    var temp = cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4);
	    return temp.toLowerCase();
	},

	/**
	 * Calculate the soundex key of a string
	 *     example 1: soundex('Kevin');
	 *     returns 1: 'K150' 
	 */
	soundex: function () {
	    var i, j, l, r, p = isNaN(p) ? 4 : p > 10 ? 10 : p < 4 ? 4 : p,
	    m = {BFPV: 1, CGJKQSXZ: 2, DT: 3, L: 4, MN: 5, R: 6},
	    r = (s = this.toUpperCase().replace(/[^A-Z]/g, "").split("")).splice(0, 1);
	    for(i = -1, l = s.length; ++i < l;){
	        for(j in m){
	            if(j.indexOf(s[i]) + 1 && r[r.length-1] != m[j] && r.push(m[j])){
	                break;
	            }
	        }
	    }
	    return r.length > p && (r.length = p), r.join("") + (new Array(p - r.length + 1)).join("0");
	},
	
	/**
	 * Pad a string to a certain length with another string
	 * @param {Int} pad_length
	 * @param {String} pad_string 
	 * @param {String} pad_type STR_PAD_LEFT|STR_PAD_BOTH|STR_PAD_RIGHT
	 *     example 1:	str = 'Kevin van Zonneveld';
	 *     				str.pad(30, '-=', 'STR_PAD_LEFT');
	 *     returns 1: '-=-=-=-=-=-Kevin van Zonneveld'
	 *     example 2: 	str = 'Kevin van Zonneveld';
	 *     				str.pad(30, '-', 'STR_PAD_BOTH');
	 *     returns 2: '------Kevin van Zonneveld-----'
	 */
	pad: function ( pad_length, pad_string, pad_type ) {
	    var half = '', pad_to_go;
	
	    var str_pad_repeater = function(s, len){
	            var collect = '', i;
	
	            while(collect.length < len) collect += s;
	            collect = collect.substr(0,len);
	
	            return collect;
	        };
			var input = this;
	    if (pad_type != 'STR_PAD_LEFT' && pad_type != 'STR_PAD_RIGHT' && pad_type != 'STR_PAD_BOTH') { pad_type = 'STR_PAD_RIGHT'; }
	    if ((pad_to_go = pad_length - input.length) > 0) {
	        if (pad_type == 'STR_PAD_LEFT') { input = str_pad_repeater(pad_string, pad_to_go) + input; }
	        else if (pad_type == 'STR_PAD_RIGHT') { input = input + str_pad_repeater(pad_string, pad_to_go); }
	        else if (pad_type == 'STR_PAD_BOTH') {
	            half = str_pad_repeater(pad_string, Math.ceil(pad_to_go/2));
	            input = half + input + half;
	            input = input.substr(0, pad_length);
	        }
	    }
	
	    return input;
	},

	/**
	 * Repeat a string
	 * @param {Int} multiplier
	 *     example 1: repeat('-=', 10);
	 *     returns 1: '-=-=-=-=-=-=-=-=-=-='
	 */
	repeat: function ( multiplier ) {
	    return new Array(multiplier+1).join(this); 
	},

	
	/**
	 * Perform the rot13 transform on a string
	 *     example 1: 	str = 'Kevin van Zonneveld';
	 *     				str.rot13();
	 *     returns 1: 'Xriva ina Mbaariryq'
	 *     example 2: 	str = 'Xriva ina Mbaariryq';
	 *     				str.rot13();
	 *     returns 2: 'Kevin van Zonneveld'
	 */
	rot13: function () {
	    return this.replace(/[A-Za-z]/g, function (c) {
	        return String.fromCharCode((((c = c.charCodeAt(0)) & 223) - 52) % 26 + (c & 32) + 65);
	    });
	},
	
	
	/**
	 * Binary safe case-insensitive string comparison
	 * @param {String} f_string2
	 *         example 1: 	str = 'Hello';
	 *         				str.casecmp('hello');
	 *         returns 1: 0
	 */
	casecmp: function ( f_string2){
	    var string1 = this.toLowerCase();
	    var string2 = f_string2.toLowerCase();
	
	    if(string1 > string2) {
	      return 1;
	    }
	    else if(string1 == string2) {
	      return 0;
	    }
	
	    return -1;
	},
	
	/**
	 * Alias of strstr()
	 * @param {Object} needle
	 * @param {Object} bool
	 * -    depends on: strstr
	 *     example 1: 	str = 'Kevin van Zonneveld';
	 *     				str.strchr('van');
	 *     returns 1: 	'van Zonneveld'
	 *     example 2: 	str = 'Kevin van Zonneveld';
	 *     				str.strchr('van', true);
	 *     returns 2: 'Kevin '
	 */
	strchr: function (needle, bool ) {
	   return this.strstr( needle, bool );
	},
	
	/**
	 * Binary safe string comparison
	 * @param {Object} str2
	 *     example 1: 	str =  'waldo';
	 *     				str.strcmp('owald' );
	 *     returns 1: 1
	 *     example 2: 	str = 'owald';
	 *     				str.strcmp('waldo' );
	 *     returns 2: -1
	 */
	strcmp: function ( str2 ) {
	    return ( ( this == str2 ) ? 0 : ( ( this > str2 ) ? 1 : -1 ) );
	},

	
	/**
	 * Strip HTML and PHP tags from a string
	 * @param {Object} allowed_tags
	 *     example 1: 	str = '<p>Kevin</p> <br /><b>van</b> <i>Zonneveld</i>';
	 *     				str.strip_tags('<i>,<b>');
	 *     returns 1: 'Kevin <b>van</b> <i>Zonneveld</i>'
	 *     example 2: 	str = '<p>Kevin <img src="someimage.png" onmouseover="someFunction()">van <i>Zonneveld</i></p>';
	 *     				str.strip_tags('<p>');
	 *     returns 2: '<p>Kevin van Zonneveld</p>'
	 *     example 3: 	str = "<a href='http://kevin.vanzonneveld.net'>Kevin van Zonneveld</a>";
	 *     				str.strip_tags("<a>");
	 *     returns 3: '<a href='http://kevin.vanzonneveld.net'>Kevin van Zonneveld</a>'
	 */
	strip_tags: function (allowed_tags) {
	    var key = '', tag = '', allowed = false;
	    var matches = allowed_array = [];
	    var allowed_keys = {};
	    var str = this;
			
	    var replacer = function(search, replace, str) {
	        var tmp_arr = [];
	        tmp_arr = str.split(search);
	        return tmp_arr.join(replace);
	    };
	    
	    // Build allowes tags associative array
	    if (allowed_tags) {
	        allowed_tags  = allowed_tags.replace(/[^a-zA-Z,]+/g, '');;
	        allowed_array = allowed_tags.split(',');
	    }
	    
	    // Match tags
	    matches = t.match(/(<\/?[^>]+>)/gi);
	    
	    // Go through all HTML tags 
	    for (key in matches) {
	        if (isNaN(key)) {
	            // IE7 Hack
	            continue;
	        }
	        
	        // Save HTML tag
	        html = matches[key].toString();
	        
	        // Is tag not in allowed list? Remove from str!
	        allowed = false;
	        
	        // Go through all allowed tags
	        for (k in allowed_array) {
	            // Init    
	            allowed_tag = allowed_array[k];
	            i = -1;
	            
	            if (i != 0) { i = html.toLowerCase().indexOf('<'+allowed_tag+'>');}
	            if (i != 0) { i = html.toLowerCase().indexOf('<'+allowed_tag+' ');}
	            if (i != 0) { i = html.toLowerCase().indexOf('</'+allowed_tag)   ;}
	            
	            // Determine
	            if (i == 0) {
	                allowed = true;
	                break;
	            }
	        }
	        
	        if (!allowed) {
	            str = replacer(html, "", str); // Custom replace. No regexing
	        }
	    }
	    
	    return str;
	},
	
	/**
	 * Find position of first occurrence of a case-insensitive string
	 * @param {Object} f_needle
	 * @param {Object} f_offset
	 *         example 1: 	str = 'ABC';
	 *         				str.stripos('a');
	 *         returns 1: 0
	 */
	stripos: function ( f_needle, f_offset ){
	    var haystack = this.toLowerCase();
	    var needle = f_needle.toLowerCase();
	    var index = 0;
	
	    if(f_offset == undefined) {
	        f_offset = 0;
	    }
	
	    if((index = haystack.indexOf(needle, f_offset)) > -1) {
	        return index;
	    }
	
	    return false;
	},

	/**
	 * Un-quote string quoted with addslashes()
	 *     example 1: 	str = 'Kevin\'s code';
	 *     				str.stripslashes();
	 *     returns 1: "Kevin's code"
	 */
	stripslashes: function () {
	    return this.replace('/\0/g', '0').replace('/\(.)/g', '$1');
	},
	
	/**
	 * Find position of first occurrence of a string
	 * @param {Object} needle
	 * @param {Object} offset
	 *     example 1: 	str = 'Kevin van Zonneveld';
	 *     				str.strpos('e', 5);
	 *     returns 1: 14
	 */
	strpos: function ( needle, offset){
	    var i = this.indexOf( needle, offset ); // returns -1
	    return i >= 0 ? i : false;
	},
	
	/**
	 * replace string by an other in the current string
	 * @param {string} search
	 * @param {string} replace
	 *  	example 1: 	str = 'Kevin van Zonneveld';
	 *  				str.strreplace(' ', '.');
	 *     	returns 1: 'Kevin.van.Zonneveld'
	 *     	example 2: 	str = '{name}, lars';
	 *     				str.strreplace(['{name}', 'l'], ['hello', 'm']);
	 *     	returns 2: 'hemmo, mars'
	 */
	strreplace: function(search, replace) {
	    var f = search, r = replace, s = this;
	    var ra = r instanceof Array, sa = s instanceof Array, f = [].concat(f), r = [].concat(r), i = (s = [].concat(s)).length;
	 
	    while (j = 0, i--) {
	        if (s[i]) {
	            while (s[i] = (s[i]+'').split(f[j]).join(ra ? r[j] || "" : r[0]), ++j in f){};
	        }
	    };
	 
	    return sa ? s : s[0];
	},
	 /** 
	 * Reverse a string
	 *     example 1: 	str = 'Kevin van Zonneveld';
	 *     				str.strrev();
	 *     returns 1: 'dlevennoZ nav niveK'
	 */
	strrev: function (  ){
	   var ret = '', i = 0;
	
	    for ( i = this.length-1; i >= 0; i-- ){
	       ret += this.charAt(i);
	    }
	
	    return ret;
	},
	
	/**
	 * Converts a string with ISO-8859-1 characters encoded with UTF-8   to single-byte ISO-8859-1
	 *     example 1: 	str = 'Kevin van Zonneveld';
	 *     				str.utf8_decode();
	 *     returns 1: 'Kevin van Zonneveld'
	 */
	utf8Decode: function () {
		var tmp_arr = [], i = ac = c = c1 = c2 = 0;
	
	    while ( i < this.length ) {
	        c = this.charCodeAt(i);
	        if (c < 128) {
	            tmp_arr[ac++] = String.fromCharCode(c); 
	            i++;
	        } else if ((c > 191) && (c < 224)) {
	            c2 = this.charCodeAt(i+1);
	            tmp_arr[ac++] = String.fromCharCode(((c & 31) << 6) | (c2 & 63));
	            i += 2;
	        } else {
	            c2 = this.charCodeAt(i+1);
	            c3 = this.charCodeAt(i+2);
	            tmp_arr[ac++] = String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
	            i += 3;
	        }
	    }
	    
	    return tmp_arr.join('');
	},
	
	/**
	 * Find first occurrence of a string
	 * @param {Object} needle
	 * @param {Object} bool
	 *     example 1:	str = 'Kevin van Zonneveld';
	 *     				str.strstr('van');
	 *     returns 1: 'van Zonneveld'
	 *     example 2: 	str = 'Kevin van Zonneveld';
	 *     				str.strstr('van', true);
	 *     returns 2: 'Kevin '
	 */
	strstr: function ( needle, bool ) {
	    var pos = 0;
	
	    pos = this.indexOf( needle );
	    if( pos == -1 ){
	        return false;
	    } else{
	        if( bool ){
	            return this.substr( 0, pos );
	        } else{
	            return this.slice( pos );
	        }
	    }
	},
	
	/**
	 * Return part of a string
	 * @param {Object} f_start
	 * @param {Object} f_length
	 *       example 1:	str = 'abcdef';
	 *       			str.substr(0, -1);
	 *       returns 1: 'abcde'
	 *       example 2: str = 2;
	 *       			str.substr(0, -6);
	 *       returns 2: ''
	 */
	substr: function ( f_start, f_length ) {
	    f_string = this+'';
	    
	    if(f_start < 0) {
	        f_start += f_string.length;
	    }
	
	    if(f_length == undefined) {
	        f_length = f_string.length;
	    } else if(f_length < 0){
	        f_length += f_string.length;
	    } else {
	        f_length += f_start;
	    }
	
	    if(f_length < f_start) {
	        f_length = f_start;
	    }
	
	    return f_string.substring(f_start, f_length);
	},
	
	/**
	 * Count the number of substring occurrences
	 * @param {Object} needle
	 * @param {Object} offset
	 * @param {Object} length
	 *     example 1: 	str = 'Kevin van Zonneveld';
	 *     				str.substr_count('e');
	 *     returns 1: 3
	 *     example 2: 	str = 'Kevin van Zonneveld';
	 *     				str.substr_count('K', 1);
	 *     returns 2: 0
	 *     example 3: 	str = 'Kevin van Zonneveld';
	 *     				str.substr_count('Z', 0, 10);
	 *     returns 3: false
	 */
	substrCount: function ( needle, offset, length ) {
	    var pos = 0, cnt = 0;
	
	    if(isNaN(offset)) offset = 0;
	    if(isNaN(length)) length = 0;
	    offset--;
	
	    while( (offset = this.indexOf(needle, offset+1)) != -1 ){
	        if(length > 0 && (offset+needle.length) > length){
	            return false;
	        } else{
	            cnt++;
	        }
	    }
	
	    return cnt;
	},
	
	/**
	 * Make a string&#039;s first character uppercase
	 *     example 1: 	str = 'kevin van zonneveld';
	 *     				str.ucfirst();
	 *     returns 1: 'Kevin van zonneveld'
	 */
	ucfirst: function(  ) {
	    var f = this.charAt(0).toUpperCase();
	    return f + this.substr(1, this.length-1);
	},
	
	/**
	 * Wraps a string to a given number of characters
	 * @param {Object} int_width
	 * @param {Object} str_break
	 * @param {Object} cut
	 *     example 1: 	str = 'Kevin van Zonneveld';
	 *     				str.wordwrap(6, '|', true);
	 *     returns 1: 'Kevin |van |Zonnev|eld'
	 */
	wordwrap: function( int_width, str_break, cut ) {
	    var m = int_width, b = str_break, c = cut;
	    var i, j, l, s, r;
	    var str = this;
	    if(m < 1) {
	        return str;
	    }
	    for(i = -1, l = (r = str.split("\n")).length; ++i < l; r[i] += s) {
	        for(s = r[i], r[i] = ""; s.length > m; r[i] += s.slice(0, j) + ((s = s.slice(j)).length ? b : "")){
	            j = c == 2 || (j = s.slice(0, m + 1).match(/\S*(\s)?$/))[1] ? m : j.input.length - j[0].length || c == 1 && m || j.input.length + (j = s.slice(m).match(/^\S*/)).input.length;
	        }
	    }
	    return r.join("\n");
	},
	
	/**
	 * Decodes URL-encoded string
	 *     example 1:	str = 'Kevin+van+Zonneveld%21';
	 *     				str.urldecode();
	 *     returns 1: 	'Kevin van Zonneveld!'
	 *     example 2:	str = 'http%3A%2F%2Fkevin.vanzonneveld.net%2F';
	 *     				str.urldecode();
	 *     returns 2: 'http://kevin.vanzonneveld.net/'
	 *     example 3: 	str = 'http%3A%2F%2Fwww.google.nl%2Fsearch%3Fq%3Dphp.js%26ie%3Dutf-8%26oe%3Dutf-8%26aq%3Dt%26rls%3Dcom.ubuntu%3Aen-US%3Aunofficial%26client%3Dfirefox-a';
	 *     				str.urldecode();
	 *     returns 3: 'http://www.google.nl/search?q=php.js&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:unofficial&client=firefox-a'
	 */
	urldecode: function(  ) {
	    var histogram = {}, histogram_r = {}, code = 0, str_tmp = [];
	    var ret = this.toString();
	    
	    var replacer = function(search, replace, str) {
	        var tmp_arr = [];
	        tmp_arr = str.split(search);
	        return tmp_arr.join(replace);
	    };
	    
	    // The histogram is identical to the one in urlencode.
	    histogram['!']   = '%21';
	    histogram['%20'] = '+';
	    
	    for (replace in histogram) {
	        search = histogram[replace]; // Switch order when decoding
	        ret = replacer(search, replace, ret) // Custom replace. No regexing   
	    }
	    
	    // End with decodeURIComponent, which most resembles PHP's encoding functions
	    ret = decodeURIComponent(ret);
	
	    return ret;
	},
	/**
	 * URL-encodes string
	 *     example 1: 	str = 'Kevin van Zonneveld!';
	 *     				str.urlencode();
	 *     returns 1: 'Kevin+van+Zonneveld%21'
	 *     example 2: 	str = 'http://kevin.vanzonneveld.net/';
	 *     				str.urlencode();
	 *     returns 2: 'http%3A%2F%2Fkevin.vanzonneveld.net%2F'
	 *     example 3: 	str = 'http://www.google.nl/search?q=php.js&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:unofficial&client=firefox-a';
	 *     				str.urlencode();
	 *     returns 3: 'http%3A%2F%2Fwww.google.nl%2Fsearch%3Fq%3Dphp.js%26ie%3Dutf-8%26oe%3Dutf-8%26aq%3Dt%26rls%3Dcom.ubuntu%3Aen-US%3Aunofficial%26client%3Dfirefox-a'
	 */
	urlencode: function (  ) {
	    var histogram = {}, histogram_r = {}, code = 0, tmp_arr = [];
	    var ret = this.toString();
	    
	    var replacer = function(search, replace, str) {
	        var tmp_arr = [];
	        tmp_arr = str.split(search);
	        return tmp_arr.join(replace);
	    };
	    
	    // The histogram is identical to the one in urldecode.
	    histogram['!']   = '%21';
	    histogram['%20'] = '+';
	    
	    // Begin with encodeURIComponent, which most resembles PHP's encoding functions
	    ret = encodeURIComponent(ret);
	    
	    for (search in histogram) {
	        replace = histogram[search];
	        ret = replacer(search, replace, ret) // Custom replace. No regexing
	    }
	    
	    // Uppercase for full PHP compatibility
	    return ret.replace(/(\%([a-z0-9]{2}))/g, function(full, m1, m2) {
	        return "%"+m2.toUpperCase();
	    });
	    
	    return ret;
	}
});
/**
 * Sexy Alert Box
 */
var SexyAlertBox=new Class({Implements:[Chain],getOptions:function(){return{name:'SexyAlertBox',zIndex:65555,onReturn:false,onReturnFunction:$empty,BoxStyles:{'width':500},OverlayStyles:{'background-color':'#000','opacity':0.7},showDuration:200,showEffect:Fx.Transitions.linear,closeDuration:100,closeEffect:Fx.Transitions.linear,moveDuration:500,moveEffect:Fx.Transitions.Back.easeOut,onShowStart:$empty,onShowComplete:$empty,onCloseStart:$empty,onCloseComplete:function(properties){this.options.onReturnFunction(this.options.onReturn)}.bind(this)}},initialize:function(options){this.i=0;this.setOptions(this.getOptions(),options);this.Overlay=new Element('div',{'id':'BoxOverlay','styles':{'display':'none','z-index':this.options.zIndex,'position':'absolute','top':'0','left':'0','background-color':this.options.OverlayStyles['background-color'],'opacity':0,'height':window.getScrollHeight()+'px','width':window.getScrollWidth()+'px'}});this.Content=new Element('div',{'id':this.options.name+'-BoxContenedor'});this.Contenedor=new Element('div',{'id':this.options.name+'-BoxContent'}).adopt(this.Content);this.InBox=new Element('div',{'id':this.options.name+'-InBox'}).adopt(this.Contenedor);this.Box=new Element('div',{'id':this.options.name+'-Box','styles':{'display':'none','z-index':this.options.zIndex+2,'position':'absolute','top':'0','left':'0','width':this.options.BoxStyles['width']+'px'}}).adopt(this.InBox);this.Overlay.injectInside(document.body);this.Box.injectInside(document.body);this.preloadImages();window.addEvent('resize',function(){if(this.options.display==1){this.Overlay.setStyles({'height':window.getScrollHeight()+'px','width':window.getScrollWidth()+'px'});this.replaceBox()}}.bind(this));window.addEvent('scroll',this.replaceBox.bind(this))},preloadImages:function(){var img=new Array(2);img[0]=new Image();img[1]=new Image();img[2]=new Image();img[0].src=this.Box.getStyle('background-image').replace(new RegExp("url\\('?([^']*)'?\\)",'gi'),"$1");img[1].src=this.InBox.getStyle('background-image').replace(new RegExp("url\\('?([^']*)'?\\)",'gi'),"$1");img[2].src=this.Contenedor.getStyle('background-image').replace(new RegExp("url\\('?([^']*)'?\\)",'gi'),"$1")},display:function(option){if(this.Transition)this.Transition.cancel();if(this.options.display==0&&option!=0||option==1){if(Browser.Engine.trident4)$$('select','object','embed').each(function(node){node.style.visibility='hidden'});this.Overlay.setStyle('display','block');this.options.display=1;this.fireEvent('onShowStart',[this.Overlay]);this.Transition=new Fx.Tween(this.Overlay,{property:'opacity',duration:this.options.showDuration,transition:this.options.showEffect,onComplete:function(){sizes=window.getSize();scrollito=window.getScroll();this.Box.setStyles({'display':'block','left':(scrollito.x+(sizes.x-this.options.BoxStyles['width'])/2).toInt()});this.replaceBox();this.fireEvent('onShowComplete',[this.Overlay])}.bind(this)}).start(this.options.OverlayStyles['opacity'])}else{if(Browser.Engine.trident4)$$('select','object','embed').each(function(node){node.style.visibility='visible'});this.queue.delay(500,this);this.Box.setStyles({'display':'none','top':0});this.Content.empty();this.options.display=0;this.fireEvent('onCloseStart',[this.Overlay]);if(this.i==1){this.Transition=new Fx.Tween(this.Overlay,{property:'opacity',duration:this.options.closeDuration,transition:this.options.closeEffect,onComplete:function(){this.fireEvent('onCloseComplete',[this.Overlay])}.bind(this)}).start(0)}}},replaceBox:function(){if(this.options.display==1){sizes=window.getSize();scrollito=window.getScroll();if(this.MoveBox)this.MoveBox.cancel();this.MoveBox=new Fx.Morph(this.Box,{duration:this.options.moveDuration,transition:this.options.moveEffect}).start({'left':(scrollito.x+(sizes.x-this.options.BoxStyles['width'])/2).toInt(),'top':(scrollito.y+(sizes.y-this.Box.offsetHeight)/2).toInt()})}},queue:function(){this.i--;this.callChain()},messageBox:function(type,message,properties,input){this.chain(function(){properties=$extend({'textBoxBtnOk':'OK','textBoxBtnCancel':'Cancel','textBoxInputPrompt':null,'password':false,'onComplete':$empty},properties||{});this.options.onReturnFunction=properties.onComplete;this.ContenedorBotones=new Element('div',{'id':this.options.name+'-Buttons'});if(type=='warning'||type=='info'||type=='error'||type=='success'){this.AlertBtnOk=new Element('input',{'id':'BoxAlertBtnOk','type':'submit','value':properties.textBoxBtnOk,'styles':{'width':'70px'}});this.AlertBtnOk.addEvent('click',function(){this.options.onReturn=true;this.display(0)}.bind(this));if(type=='warning')this.clase='BoxAlert';else if(type=='error')this.clase='BoxError';else if(type=='info')this.clase='BoxInfo';else if(type=='success')this.clase='BoxSuccess';this.Content.setProperty('class',this.clase).set('html',message);this.AlertBtnOk.injectInside(this.ContenedorBotones);this.ContenedorBotones.injectInside(this.Content);this.display(1)}else if(type=='confirm'){this.ConfirmBtnOk=new Element('input',{'id':'BoxConfirmBtnOk','type':'submit','value':properties.textBoxBtnOk,'styles':{'width':'70px'}});this.ConfirmBtnCancel=new Element('input',{'id':'BoxConfirmBtnCancel','type':'submit','value':properties.textBoxBtnCancel,'styles':{'width':'70px'}});this.ConfirmBtnOk.addEvent('click',function(){this.options.onReturn=true;this.display(0)}.bind(this));this.ConfirmBtnCancel.addEvent('click',function(){this.options.onReturn=false;this.display(0)}.bind(this));this.Content.setProperty('class','BoxConfirm').set('html',message);this.ConfirmBtnOk.injectInside(this.ContenedorBotones);this.ConfirmBtnCancel.injectInside(this.ContenedorBotones);this.ContenedorBotones.injectInside(this.Content);this.display(1)}else if(type=='prompt'){this.PromptBtnOk=new Element('input',{'id':'BoxPromptBtnOk','type':'submit','value':properties.textBoxBtnOk,'styles':{'width':'70px'}});this.PromptBtnCancel=new Element('input',{'id':'BoxPromptBtnCancel','type':'submit','value':properties.textBoxBtnCancel,'styles':{'width':'70px'}});type=properties.password?'password':'text';this.PromptInput=new Element('input',{'id':'BoxPromptInput','type':type,'value':input,'styles':{'width':'250px'}});this.PromptBtnOk.addEvent('click',function(){this.options.onReturn=this.PromptInput.value;this.display(0)}.bind(this));this.PromptBtnCancel.addEvent('click',function(){this.options.onReturn=false;this.display(0)}.bind(this));this.Content.setProperty('class','BoxPrompt').set('html',message+'<br />');this.PromptInput.injectInside(this.Content);new Element('br').injectInside(this.Content);this.PromptBtnOk.injectInside(this.ContenedorBotones);this.PromptBtnCancel.injectInside(this.ContenedorBotones);this.ContenedorBotones.injectInside(this.Content);this.display(1)}else{this.options.onReturn=false;this.display(0)}});this.i++;if(this.i==1)this.callChain()},warning:function(message,properties){this.messageBox('warning',message,properties)},success:function(message,properties){this.messageBox('success',message,properties)},info:function(message,properties){this.messageBox('info',message,properties)},error:function(message,properties){this.messageBox('error',message,properties)},confirm:function(message,properties){this.messageBox('confirm',message,properties)},prompt:function(message,input,properties){this.messageBox('prompt',message,properties,input)}});SexyAlertBox.implement(new Events,new Options); 
/*  Window.Growl, version 2.0: http://icebeat.bitacoras.com
 *  Daniel Mota aka IceBeat <daniel.mota@gmail.com>
 *	Updated to 1.2b2 by Paul Streise <paulstreise@gmail.com>
 *  Updated to 1.2 by Lennart Pilon (http://ljpilon.nl)
 *  Updated to 1.3 by Florian Collot
 *  Dependencies :{
 *  	Mootools 1.2
 *  	Display
 *  	Array
 *  }
--------------------------------------------------------------------------*/

if (typeof slsBuild =="object" && typeof slsBuild.site == "object" && slsBuild.site.domainName != ""  && slsBuild.paths.coreImg != "")
{
	var Gr0wl = {};
	var Gr0wlImgLoaded = false;
	Gr0wl.Base = new Class({
	
		Implements: Options,	
		options: {
			image: 'http://'+slsBuild.site.domainName+'/'+slsBuild.paths.coreImg+'/dialog-information.jpg',
			imageHeight : 50,
			imageWidth : 50,
			title: 'SillySmart',
			text: 'Javascript Developer Alerts',
			duration: 0,
			textColor: '#FFFFFF',
			titleColor: '#FFFFFF'
		},
		
		initialize: function(imageTop, imageBot, options) {
			this.images = new Asset.images([imageTop, imageBot], { onComplete: this.create.bind(this)});
			this.setOptions(options);
			return this.show.bind(this);
		},
		
		create: function(styles) {
			Gr0wlImgLoaded = true;
			this.block = new Element('div').setStyles(
				$extend(
				{
					'position': 'absolute',
					'display': 'none',
					'z-index':'999',
					'color':'#fff',
					'background-color': 'transparent',
					'font': '12px/14px "Lucida Grande", Arial, Helvetica, Verdana, sans-serif'
				},
				styles.div)
				).setOpacity(0).injectInside(document.body);
			
			this.topDiv = new Element('div').setStyles({
				'display' 	: 'block',
				'position'	: 'relative',
				'color'		: '#FFF',
				'width'		: '100%',
				'height'	: '12px',
				'background-image' : 'url('+this.images[0].get('src')+')',
				'background-repeat': 'no-repeat'			
			});
			if (Browser.Engine.trident)
				this.topDiv.setStyles({
					'background'	: 'none',
					'filter'		: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=\'true\', src=\''+this.images[0].get('src')+'\', sizingMethod=\'scale\')'
				});
			this.topDiv.injectInside(this.block);
			
			this.contentDiv = new Element('div').setStyles({
				'float'	: 'left',
				'background-color' : '#000',
				'width'		: '100%'
			});
						
			this.contentDiv.injectInside(this.block);
			
			this.bottomDiv = new Element('div').setStyles({
				'display' 	: 'block',
				'float'	: 'left',
				'width'		: '100%',
				'height'	: '12px',
				'background-image' : 'url('+this.images[1].get('src')+')',
				'background-repeat': 'no-repeat'
			});
			if (Browser.Engine.trident)
				this.bottomDiv.setStyles({
					'background'	: 'none',
					'filter'		: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=\'true\', src=\''+this.images[1].get('src')+'\', sizingMethod=\'crop\')'
				});
			this.bottomDiv.injectInside(this.block);
			new Element('img').setStyles(styles.img).injectInside(this.contentDiv);
			new Element('h3').setStyles(styles.h3).injectInside(this.contentDiv);
			new Element('p').setStyles(styles.p).injectInside(this.contentDiv);
			
		},
		
		show: function(options) {
			
			options = $merge(this.options, options);
			options.position = this.getPosition();
			var elements = this.block.clone();
			elements.injectInside(document.body);
			elements.setStyles(options.position);
					
			var inEl = elements.getChildren().getChildren();
			inEl[1][0].setProperties({src: options.image, height: options.imageHeight, width: options.imageWidth});
			
			inEl[1][1].setStyle('color', options.titleColor).set('html', options.title);
			inEl[1][2].setStyle('color', options.textColor).set('html', options.text);
			var bottomEl = elements.getChildren();
			bottomEl[2].set('id', 'growl-ss-bottom-'+Gr0wlSmokeQueue.getLast());
			var effect = new Fx.Morph(elements, {duration:400});
			effect.set({
				'opacity': 0
			});
			effect.start({
				'opacity': 0.75
			});
			if (options.duration == 0) {
				var topId = 'growl-ss-top-'+Gr0wlSmokeQueue.getLast();
				elements.set('id', topId);
				elements.setStyle('cursor', 'pointer');
				elements.addEvent('click', function(){
					Growl.Smoke.hideEx(topId);
				});
			}
			else 
				this.hide.delay(options.duration * 1000, this, [elements]);
			
			
			
			
		},
		
		hide: function(elements) {
			var effect = new Fx.Morph(elements, {
				duration:400,
				onComplete:function(){
					elements.empty().erase();
				}});
			effect.set({
				'opacity': 0.75
			});
			effect.start({
				'opacity': 0
			});
		},
	
		getPosition: function() {
			return {'top': '200px', 'right':'200px', 'display':'block'};
		}
		
	});
	
	
	Gr0wl.Smoke = new Class ({
	
		Extends: Gr0wl.Base,	
		create: function() {
			if (Gr0wlSmokeQueue == 0) {
				
				Gr0wlSmokeQueue = new Array();
				this.topPos = new Array();
			}
			
			
			this.parent({
				div:
					{
						'width':'298px'
					},
				img:
					{
						'float':'left',
						'margin':'0 12px 12px 12px'
					},
				h3:
					{
						'margin':'0',
						'padding':'0px 0px 10px 0px',
						'font-size':'13px'
					},
				
				p:
					{
						'margin':'0px 10px',
						'font-size':'12px'	
					}
			});
		},
		getPosition: function() {
			var last = Gr0wlSmokeQueue.getLast();
			
			var top = 10;
			if (last != null)
			{
				top += (Display.getY($('growl-ss-bottom-'+last)))+12;
			}
			var pos = {'top':top+'px', 'right':'10px', 'display':'block'};
			Gr0wlSmokeQueue.push(last+1);
			return pos
		},
	
		hide: function(elements) {
			Gr0wlSmokeQueue.shift();
			this.parent(elements);
		}
		
	});
	var Gr0wlSmokeQueue = new Array();
	
	var Growl = function(options) {
		if(Growl[options.type]) Growl[options.type].call(options);
		else Growl.Smoke(options);
	};
	
	/*
	 *	Change url image
	 *	Example:
		Growl.Smoke({
		title: 'Window.Growl By Daniel Mota',
		text: 'http://icebeat.bitacoras.com',
		image: 'growl.jpg',
		duration: 2
		});
	*/
	window.addEvent('domready',function() {
		Growl.Smoke = new Gr0wl.Smoke('http://'+slsBuild.site.domainName+'/'+slsBuild.paths.coreImg+'smokeTop.png', 'http://'+slsBuild.site.domainName+'/'+slsBuild.paths.coreImg+'smokeBottom.png');
		Growl.Smoke.hideEx = function(elements){
			elements = $(elements);
			if (Gr0wlSmokeQueue.has(elements))
				GrOwlSmokeQueue.slice()
			var effect = new Fx.Morph(elements, {
					duration:400,
					onComplete:function(){
						elements.empty().erase();
					}});
				effect.set({
					'opacity': 0.75
				});
				effect.start({
					'opacity': 0
				});
		};
		Note.displayStartup();
	});
}
/**
 * Class Note
 * Display All SillySmart Js Notes
 * Based on Mootools and required growl changed by 58062
 * @author 58062
 */
function Note(){}
Note.isActive = false;
Note.domReady = [];
Note.warning = function(string, time){
	if (Note.isActive == true) {
		if (time == null) 
			time = 5;
		Growl.Smoke({
			image: "http://"+slsBuild.site.domainName+"/"+slsBuild.paths.coreImg+"dialog-warning.jpg",
			title: "SillySmart Warning",
			textColor: "#FFB55F",
			text: string,
			duration: time
		});
	}
	else 
		Note.domReady.push("Note.warning('"+string+"', "+time+");");
	
};
Note.error = function(string, time){
	if (Note.isActive == true) {
		if (time == null) 
			time = 0;
		Growl.Smoke({
			image: "http://"+slsBuild.site.domainName+'/'+slsBuild.paths.coreImg+"dialog-error.jpg",
			title: "SillySmart Error",
			titleColor: "#EF0E0E",
			textColor: "#DF8B8B",
			text: string,
			duration: time
		});
	}
	else
		Note.domReady.push("Note.error('"+string+"', "+time+");");
};
Note.tick = function(string, time){
	if (Note.isActive == true) {
		if (time == null) 
			time = 5;
		Growl.Smoke({
			image: "http://"+slsBuild.site.domainName+"/"+slsBuild.paths.coreImg+"dialog-success.jpg",
			title: "SillySmart Note",
			textColor: "#4A9F3B",
			text: string,
			duration: time
		});
	}
	else 
		Note.domReady.push("Note.tick('"+string+"', "+time+");");
	
};
Note.intervalStartup = null;
Note.displayStartup = function() {
	if (Gr0wlImgLoaded === false){
		Note.intervalStartup = setInterval('Note.displayStartup()', 500);
		return; 
	}
	else{
		clearTimeout(Note.intervalStartup);
		Note.isActive = true;
		/*for (key in Note.domReady)
			eval(Note.domReady[key]);*/
		for (var i=0; i<Note.domReady.length;i++){
			eval(Note.domReady[i]);
		}
		
		return;
	}
}
