// String prototype extension

if (!String.prototype.ltrim) {
	String.prototype.ltrim = function(charlist) {
		var str = this;
		charlist = !charlist ? ' \s\xA0' : (charlist+'').replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '\$1');
		var re = new RegExp('^[' + charlist + ']+', 'g');
		return (str+'').replace(re, '');		
	}
}

if (!String.prototype.rtrim) {
	String.prototype.rtrim = function(charlist) {
		var str = this;
		charlist = !charlist ? ' \s\xA0' : (charlist+'').replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '\$1');
		var re = new RegExp('[' + charlist + ']+$', 'g');
		return (str+'').replace(re, '');
	}
}

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

}

if (!String.prototype.pad) {
	/* Pad a string to a certain length with another string. */
	String.prototype.pad = function(pad_length, pad_string, pad_type) {
		var input = this;
		var str_pad_repeater = function(s, len) {
			var collect = '', i;
			while(collect.length < len) collect += s;
				collect = collect.substr(0,len);
			return collect;
		};

		input += '';

		if (pad_type != 'PAD_LEFT' && pad_type != 'PAD_RIGHT' && pad_type != 'PAD_BOTH') { pad_type = 'PAD_RIGHT'; }
		if ((pad_to_go = pad_length - input.length) > 0) {
			if (pad_type == 'PAD_LEFT') { input = str_pad_repeater(pad_string, pad_to_go) + input; }
			else if (pad_type == 'PAD_RIGHT') { input = input + str_pad_repeater(pad_string, pad_to_go); }
			else if (pad_type == '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;
	}
}

if (!String.prototype.shuffle) {
	/* Randomly shuffles a string. */
	String.prototype.shuffle = function() {
		var str = this;
		var tot = this.length;
    
		var getRandomInt = function (max) {
			return Math.floor(Math.random() * (max + 1));
		};
		var newStr = '', rand = 0;
    
		for (i=0; i<tot; i++) {
			rand = getRandomInt(str.length-1);
			newStr += str[rand];
			str = str.substring(0, rand)+str.substr(rand+1);
		}
    
		return newStr;		
	}
}

if (!String.prototype.stripTags) {
	/* Strip HTML and PHP tags from a string. */
	String.prototype.stripTags = function(allowed_tags) {
		var str = this;
		var key = '', allowed = false;
		var matches = [];
		var allowed_array = [];
		var allowed_tag = '';
		var i = 0;
		var k = '';
		var html = '';
		var replacer = function(search, replace, str) {
			return str.split(search).join(replace);
		};
		if (allowed_tags) {
			allowed_array = allowed_tags.match(/([a-zA-Z]+)/gi);
		}
		str += '';
		matches = str.match(/(<\/?[^>]+>)/gi);
	    for (key in matches) {
			if (isNaN(key)) {
				continue;
			}
			html = matches[key].toString();
			allowed = false;
			for (k in allowed_array) {
				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)   ;}
				if (i == 0) {
					allowed = true;
					break;
				}
			}

			if (!allowed) {
				str = replacer(html, "", str);
			}
		}
		return str;		
	}
}

if (!String.prototype.reverse) {
	/* Reverse a string. */
	String.prototype.reverse = function() {
		var string = this;
		var ret = '', i = 0;

		string += '';
		for ( i = string.length-1; i >= 0; i-- ){
			ret += string.charAt(i);
		}

		return ret;		
	}
}

if (!String.prototype.startsWith) {
	String.prototype.startsWith = function(toSearch) {
		if (this.indexOf(toSearch) == 0) {
			return true;
		} else {
			return false;
		}
	}
}

if (!String.prototype.endsWith) {
	String.prototype.endsWith = function(toSearch) {
		if (this.indexOf(toSearch) == (this.length-toSearch.length)) {
			return true;
		} else {
			return false;
		}
	}
}

// Math prototype extension

if (!Math.acosh) {
	Math.acosh = function(arg) {
		return Math.log(arg + Math.sqrt(arg*arg-1));
	}
}

if (!Math.asinh) {
	Math.asinh = function(x) {
		return Math.log(arg + Math.sqrt(arg*arg+1));
	}
}

if (!Math.atanh) {
	Math.atanh = function(arg) {
		return 0.5 * Math.log((1+arg)/(1-arg));
	}
}

if (!Math.cosh) {
	Math.cosh = function(arg) {
		return (Math.exp(arg) + Math.exp(-arg))/2;
	}
}

if (!Math.sinh) {
	Math.sinh = function(arg) {
		return (Math.exp(arg) - Math.exp(-arg))/2;
	}
}

if (!Math.tanh) {
	Math.tanh = function(arg) {
		return (Math.exp(arg) - Math.exp(-arg)) / (Math.exp(arg) + Math.exp(-arg));
	}
}

if (!Math.rad) {
	Math.rad = function(arg) {
		return (arg/180)*Math.PI;
	}
}

if (!Math.deg) {
	Math.deg = function(arg) {
		return (angle/Math.PI) * 180;
	}
}

if (!Math.convert) {
	Math.convert = function(number, fromBase, toBase) {
		return parseInt(number+'', fromBase+0).toString(toBase+0);
	}
}

Math.log = function(arg, base) {
    if (base === undefined) {
        return Math.log(arg);
    } else {
        return Math.log(arg)/Math.log(base);
    }	
}

// Array prototype extension

if (!window._arrayPointers) {
	window._arrayPointers = [];
}

if (!Array.prototype.combine) {
	/* combine: return an associative array containing the element of this array as keys
	   and the element of the parameter array as values.
	*/
	Array.prototype.combine = function(v) {
		var new_array = {};
		if( !v || v.constructor !== Array) return false;
		var elemcount = v.length;
		if(this.length != v.length) return false;
		for ( i=0; i < this.length; i++ ) {
			if (!(this[i] instanceof Object) && !(v[i] instanceof Object)) {
				new_array[this[i]] = v[i];
			}
		}
		return new_array;
	}
}

if (!Array.prototype.diff) {
	/* Computes the difference between this array and the one passed as parameter
	   and return an associative array with key equals to the index of the different 
	   elements and values the element contained in the passed array and not in this one.
    */
	Array.prototype.diff = function(v) {
		var retArr = {};
		var k1 = '';
		var k = '';
		arr1keys:
		for (k1=0;k1<v.length;k1++) {
			for (k=0;k<this.length;k++) {
				if (this[k] === v[k1]) {
						continue arr1keys; 
				}
			}
			retArr[k1] = v[k1];
		}
		return retArr;		
	}
}

if (!Array.prototype.fill) {
	/* Fill the specified portion of this array with the value passed as parameter. */
	Array.prototype.fill = function(start, num, value) {
		for (idx=start; idx<=num; idx++) {
			this[idx] = value;
		}
	}
}

if (!Array.prototype.filter) {
	/* Fill an array with the value that satisfy the filter passed as parameter.
	   The filter is a callback function.
	*/
	Array.prototype.filter = function(f) {
		var retObj = {};
		for (k in this) {
			if (f(this[k])) {
				retObj[k] = this[k];
			}
		}
		return retObj;	
	}
}

if (!Array.prototype.map) {
	/* Fill an array with the value returned by the callback funcion passed as parameter. */
	Array.prototype.map = function(f) {
		var retObj = [];
		for (var k in this) {
			retObj.push(f(this[k]));
		}
		return retObj;
	}
}

if (!Array.prototype.contains) {
	/* Return true if the array contains the passed value, false otherwise. */
	Array.prototype.contains = function(s) {
		for (var key in this) {
			if (this[key] == s) return true;
		}
		return false;
	}
}

if (!Array.prototype.unique) {
	/* Return an array with the same values of this one but without duplicated. */
	Array.prototype.unique = function() {
		var tmp = [];
		var newArr = [];
		for (var key in this) {
			if (!tmp.contains(this[key])) {
				newArr.push(this[key]);
			}
			tmp.push(this[key]);
		}
		return newArr;
	}
}

if (!Array.prototype.current) {
	/* Return the current array element according to related cursor. */
	Array.prototype.current = function() {
		var pointers = window._arrayPointers;;
		if (pointers.indexOf(this) === -1) {
			pointers.push(this, 0);
		}
		var arrpos = pointers.indexOf(this);
		var cursor = pointers[arrpos+1];
		if (this instanceof Array) {
			return this[cursor] || false;
		}
		var ct = 0;
		for (var k in this) {
			if (ct === cursor) {
				return arr[k];
			}
			ct++;
		}
		return false;		
	}
}

if (!Array.prototype.last) {
	/* Return the last array element. */
	Array.prototype.last = function() {
		var pointers = window._arrayPointers;
		if (pointers.indexOf(this) === -1) {
			pointers.push(this, 0);
		}
		var arrpos = pointers.indexOf(this);
		if (!(this instanceof Array)) {
			var ct = 0;
			for (var k in this) {
				ct++;
				var val = this[k];
			}
			if (ct === 0) {
				return false; // Empty
			}
			pointers[arrpos+1] = ct - 1;
			return val;
		}
		if (this.length === 0) {
			return false;
		}
		pointers[arrpos+1] = this.length - 1;
		return this[pointers[arrpos+1]];		
	}
}

if (!Array.prototype.next) {
	/* Return the next array element according to related cursor. */
	Array.prototype.next = function() {
		var pointers = window._arrayPointers;;
		if (pointers.indexOf(this) === -1) {
			pointers.push(this, 0);
		}
		var arrpos = pointers.indexOf(this);
		var cursor = pointers[arrpos+1];
		if (!(this instanceof Array)) {
			var ct = 0;
			for (var k in this) {
				if (ct === cursor+1) {
					pointers[arrpos+1] += 1;
					return this[k];
				}
				ct++;
			}
			return false; // End
		}
		if (this.length === 0 || cursor === (this.length-1)) {
			return false;
		}
		pointers[arrpos+1] += 1;
		return this[pointers[arrpos+1]];		
	}
}

if (!Array.prototype.prev) {
	/* Return the previous array element according to related cursor. */
	Array.prototype.prev = function() {
		var pointers = window._arrayPointers;;
		if (pointers.indexOf(this) === -1) {
			pointers.push(this, 0);
		}
		var arrpos = pointers.indexOf(this);
		var cursor = pointers[arrpos+1];
		if (pointers.indexOf(this) === -1 || cursor === 0) {
			return false;
		}
		if (!(this instanceof Array)) {
			var ct = 0;
			for (var k in this) {
				if (ct === cursor-1) {
					pointers[arrpos+1] -= 1;
					return this[k];
				}
				ct++;
			}
		// Shouldn't reach here
		}
		if (this.length === 0) {
			return false;
		}
		pointers[arrpos+1] -= 1;
		return this[pointers[arrpos+1]];		
	}
}

if (!Array.prototype.first) {
	/* Return the first array element. */
	Array.prototype.first = function() {
		var pointers = window._arrayPointers;;
		if (pointers.indexOf(this) === -1) {
			pointers.push(this, 0);
		}
		var arrpos = pointers.indexOf(this);
		if (!(this instanceof Array)) {
			for (var k in this) {
				if (pointers.indexOf(this) === -1) {
					pointers.push(this, 0);
				} else {
					pointers[arrpos+1] = 0;
				}
				return this[k];
			}
			return false; // Empty
		}
		if (this.length === 0) {
			return false;
		}
		pointers[arrpos+1] = 0;
		return this[pointers[arrpos+1]];		
	}
}

if (!Array.prototype.hasNext) {
	/* Check if the array has at least another element at current cursor. */
	Array.prototype.hasNext = function() {
		var pointers = window._arrayPointers;;
		if (pointers.indexOf(this) === -1) {
			pointers.push(this, 0);
		}
		var arrpos = pointers.indexOf(this);
		var cursor = pointers[arrpos+1];
		if (this.length === 0 || cursor === (this.length-1)) {
			return false;
		} else {
			return true;
		}
	}
}

// JSON encode/decode object

var JSON = new Object();

JSON.encode = function(mixed_val) {
    var indent;
    var value = mixed_val;
    var i;

    var quote = function (string) {
        var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
        var meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        };

        escapable.lastIndex = 0;
        return escapable.test(string) ?
        '"' + string.replace(escapable, function (a) {
            var c = meta[a];
            return typeof c === 'string' ? c :
            '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        }) + '"' :
        '"' + string + '"';
    }

    var str = function(key, holder) {
        var gap = '';
        var indent = '    ';
        var i = 0;          // The loop counter.
        var k = '';          // The member key.
        var v = '';          // The member value.
        var length = 0;
        var mind = gap;
        var partial = [];
        var value = holder[key];

        if (value && typeof value === 'object' &&
            typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }
        
        switch (typeof value) {
            case 'string':
                return quote(value);

            case 'number':
                return isFinite(value) ? String(value) : 'null';

            case 'boolean':
            case 'null':
                return String(value);

            case 'object':
                if (!value) {
                    return 'null';
                }

                gap += indent;
                partial = [];

                if (Object.prototype.toString.apply(value) === '[object Array]') {
                    length = value.length;
                    for (i = 0; i < length; i += 1) {
                        partial[i] = str(i, value) || 'null';
                    }
                    v = partial.length === 0 ? '[]' :
                    gap ? '[\n' + gap +
                    partial.join(',\n' + gap) + '\n' +
                    mind + ']' :
                    '[' + partial.join(',') + ']';
                    gap = mind;
                    return v;
                }

                for (k in value) {
                    if (Object.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
                v = partial.length === 0 ? '{}' :
                gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
                mind + '}' : '{' + partial.join(',') + '}';
                gap = mind;
                return v;
        }
    };

    return str('', {
        '': value
    });
}

JSON.decode = function(str_json) {

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
    var j;
    var text = str_json;

    var walk = function(holder, key) {
        var k, v, value = holder[key];
        if (value && typeof value === 'object') {
            for (k in value) {
                if (Object.hasOwnProperty.call(value, k)) {
                    v = walk(value, k);
                    if (v !== undefined) {
                        value[k] = v;
                    } else {
                        delete value[k];
                    }
                }
            }
        }
        return reviver.call(holder, key, value);
    }

    cx.lastIndex = 0;
    if (cx.test(text)) {
        text = text.replace(cx, function (a) {
            return '\\u' +
            ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        });
    }

    if (/^[\],:{}\s]*$/.
        test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
            replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
            replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

		j = eval('(' + text + ')');

        return typeof reviver === 'function' ?
        walk({
            '': j
        }, '') : j;
    }

    throw new SyntaxError('json_decode');
}

// BASE64 encode/decode object

var BASE64 = new Object();

BASE64.encode = function(data) {
    var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    var o1, o2, o3, h1, h2, h3, h4, bits, i = ac = 0, enc="", tmp_arr = [];

    if (!data) {
        return data;
    }

    data = utf8_encode(data+'');
    
    do { // pack three octets into four hexets
        o1 = data.charCodeAt(i++);
        o2 = data.charCodeAt(i++);
        o3 = data.charCodeAt(i++);

        bits = o1<<16 | o2<<8 | o3;

        h1 = bits>>18 & 0x3f;
        h2 = bits>>12 & 0x3f;
        h3 = bits>>6 & 0x3f;
        h4 = bits & 0x3f;

        // use hexets to index into b64, and append result to encoded string
        tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
    } while (i < data.length);
    
    enc = tmp_arr.join('');
    
    switch( data.length % 3 ){
        case 1:
            enc = enc.slice(0, -2) + '==';
        break;
        case 2:
            enc = enc.slice(0, -1) + '=';
        break;
    }

    return enc;	
}

BASE64.decode = function(data) {
    var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, dec = "", tmp_arr = [];

    if (!data) {
        return data;
    }

    data += '';

    do {  // unpack four hexets into three octets using index points in b64
        h1 = b64.indexOf(data.charAt(i++));
        h2 = b64.indexOf(data.charAt(i++));
        h3 = b64.indexOf(data.charAt(i++));
        h4 = b64.indexOf(data.charAt(i++));

        bits = h1<<18 | h2<<12 | h3<<6 | h4;

        o1 = bits>>16 & 0xff;
        o2 = bits>>8 & 0xff;
        o3 = bits & 0xff;

        if (h3 == 64) {
            tmp_arr[ac++] = String.fromCharCode(o1);
        } else if (h4 == 64) {
            tmp_arr[ac++] = String.fromCharCode(o1, o2);
        } else {
            tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
        }
    } while (i < data.length);

    dec = tmp_arr.join('');
    dec = utf8_decode(dec);

    return dec;
}

function utf8_decode ( str_data ) {

    var tmp_arr = [], i = 0, ac = 0, c1 = 0, c2 = 0, c3 = 0;
    
    str_data += '';
    
    while ( i < str_data.length ) {
        c1 = str_data.charCodeAt(i);
        if (c1 < 128) {
            tmp_arr[ac++] = String.fromCharCode(c1);
            i++;
        } else if ((c1 > 191) && (c1 < 224)) {
            c2 = str_data.charCodeAt(i+1);
            tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
            i += 2;
        } else {
            c2 = str_data.charCodeAt(i+1);
            c3 = str_data.charCodeAt(i+2);
            tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
            i += 3;
        }
    }

    return tmp_arr.join('');
}// }}}

function utf8_encode ( string ) {

    string = (string+'').replace(/\r\n/g, "\n").replace(/\r/g, "\n");

    var utftext = "";
    var start, end;
    var stringl = 0;

    start = end = 0;
    stringl = string.length;
    for (var n = 0; n < stringl; n++) {
        var c1 = string.charCodeAt(n);
        var enc = null;

        if (c1 < 128) {
            end++;
        } else if((c1 > 127) && (c1 < 2048)) {
            enc = String.fromCharCode((c1 >> 6) | 192) + String.fromCharCode((c1 & 63) | 128);
        } else {
            enc = String.fromCharCode((c1 >> 12) | 224) + String.fromCharCode(((c1 >> 6) & 63) | 128) + String.fromCharCode((c1 & 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;
}// }}}

// J43S object

function _getReqObject() {
	if (typeof XMLHttpRequest != "undefined") {
			return new XMLHttpRequest();
	} else if (window.ActiveXObject) {
		var versions = ["MSXML2.XMLHttp.5.0", 
		                "MSXML2.XMLHttp.4.0", 
						"MSXML2.XMLHttp.3.0", 
						"MSXML2.XMLHttp",
					    "Microsoft.XMLHttp"];
		for (i = 0; i < versions.length; i++) {
			try	{
				var obj = new ActiveXObject(versions[i]);
				return obj;
			} catch (e)	{
				// Ignore
			}
		}
	}
	throw new Error("Could not create the XMLHttpRequest object");
}

function _scriptExists(name) {
    var _q = _getReqObject();;
    _q.open('HEAD', name, false);
    _q.send(null);
	_s = _q.status;
	delete _q;
    if (_s == 200){
		return true;
    }
    return false;
}

function _send(url, parms) {
	var _q = null;
	_q = _getReqObject();
	_q.open("POST", url, false);	
	_q.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	_q.setRequestHeader("Content-length", parms.length);
	_q.setRequestHeader("Connection", "close");
	try {
		_q.send(parms);
	} catch(e) {
		alert(e);
	};
	if (_q.responseText.indexOf("<b>") != -1) {
		alert(_q.responseText);
	}
	__tmp = JSON.decode(BASE64.decode(_q.responseText));
	delete _q;
	return __tmp;
}

function _getMappings() {
	_q = _getReqObject();
	_q.open("GET", "./conf/mappings.txt", false);	
	_q.send(null);
	return _q.responseText;
}

function _createFunction(name, args, code) {
	var tmp = name+" = function ("+args+") {";
	tmp += code;
	tmp +="}";
	return eval(tmp);
}

function _argsToQueryString(parms) {
	var tmp = "";
	for (i=0;i<parms.length;i++) {
		tmp += ("p"+i+"="+BASE64.encode(parms[i])+"&");
		//tmp += ("p"+i+"="+parms[i]+"&");
	}
	//return tmp.substr(0, tmp.length-1);
	return "t="+(new Date().getTime())+"&"+tmp.substr(0, tmp.length-1);
}

var J43S = new Object();

J43S.base3Sdir = "./lib/scripts";
J43S.ext3S = "php";

J43S.init = function() {
	var tmp = _getMappings().split(",");
	for (i=0; i<tmp.length; i++) {
		if (_scriptExists(J43S.get3Sbasedir()+"/"+tmp[i]+".php")) {
			J43S.register(tmp[i]);
		}
	}
}

J43S.register = function(name) {
	eval(name+"=_createFunction('"+name+"', '','return _send(\\\'"+J43S.get3Sbasedir()+"/"+name+"."+J43S.get3Sextension()+"\\\', _argsToQueryString(arguments));');");
}

J43S.unregister = function(name) {
	eval("delete "+name);
}

J43S.set3Sbasedir = function(dir) {
	J43S.base3Sdir = dir;
}

J43S.get3Sbasedir = function() {
	return J43S.base3Sdir;
}

J43S.set3Sextension = function(ext) {
	J43S.ext3S = ext;
}

J43S.get3Sextension = function() {
	return J43S.ext3S;
}

J43S.getRegisteredList = function() {
	return _getMappings();
}

// Logger object

var Level = {DEBUG:0, 
    	     INFO:1,
			 WARN:2,
			 ERROR:3,
			 FATAL:4,
			 PROFILE:5}
			 
function Logger(elem, level) {
	this.elem  = elem;
	this.level = level;
}

Logger.prototype.log = function(level, msg) {
	if (level >= this.level) {
		var color = "black";
		var l = "DEBUG";
		switch(level) {
			case Level.DEBUG:
				color = "blue";
				break;
			case Level.INFO:
				l = "INFO";
				color = "green";
				break;
			case Level.WARN:
				l = "WARN";
				color = "yellow";
				break;
			case Level.ERROR:
				l = "ERROR";
				color = "orange";
				break;
			case Level.FATAL:
				l = "FATAL";
				color = "red";
				break;
		}
		var f= "";
		f = this.log.caller.toString();
		f = f.substring('function '.length);
		f = f.substring(0, f.indexOf('('));	
		var cap = (new Date().toLocaleString()) + " [" + f + "]";
		if (document.getElementById(this.elem)) {
			if (level<Level.WARN) {
				document.getElementById(this.elem).innerHTML += "<font color=\""+color+"\">"+cap+" - "+l+": "+msg+"</font><br/>";
			} else {
				document.getElementById(this.elem).innerHTML += "<font color=\""+color+"\">"+cap+" - <b>"+l+": "+msg+"</b></font><br/>";
			}
		}
	}
}

// Profiler object

function Profiler() {
	this._toCheck = {};
}

Profiler.prototype.start = function(_who) {
	var _entry = new ProfilingEntry(_who, _getCurrentMillis(), -1);
	if (this._toCheck[_who]) {
		return this._toCheck[_who].push(_entry);
	} else {
		this._toCheck[_who] = [_entry];
		return 0;
	}
}

Profiler.prototype.stop = function(_who, _which) {
	_tmp = this._toCheck[_who][_which];
	_tmp.end = _getCurrentMillis();
	while (_tmp.end==-1) {}
	this._toCheck[_who][_which] = _tmp;
}

Profiler.prototype.getEntries = function(_who) {
	return this._toCheck[_who];
}

Profiler.prototype.getLastEntry = function(_who) {
	_l = this._toCheck[_who].length-1;
	return this._toCheck[_who][_l];
}

Profiler.prototype.getAverageExecutionTime = function(_who) {
	_a = this._toCheck[_who];
	_t = 0;
	for (_idx=0;_idx<_a.length;_idx++) {
		_t += _a[_idx].getElapsed();
	}
	return Math.round(_t/_a.length);
}

Profiler.prototype.getLastExecutionTime = function(_who) {
	return this.getLastEntry(_who).getElapsed();
}

Profiler.prototype.getExecutionCount = function(_who) {
	_a = this._toCheck[_who];
	return _a.length;
}

function ProfilingEntry(_who, _start, _end) {
	this.who   = _who;
	this.start = _start;
	this.end   = _end;
}

ProfilingEntry.prototype.getName = function() {
	return this.who;
}

ProfilingEntry.prototype.getStart = function() {
	return this.start;
}

ProfilingEntry.prototype.getEnd = function() {
	return this.end;
}

ProfilingEntry.prototype.getElapsed = function() {
	return (this.end-this.start);
}

// Ajax Request object

function AjaxRequest() {
	this.states = {
		UNSENT : 0,
		OPENED : 1,
		HEADERS_RECEIVED : 2,
		LOADING : 3,
		DONE : 4
	}
	this.request = _getReqObject();
	this.url = null;
	this.options = {method : "post",
					parameters : "", 
	 		        asynchronous : true,
	 		        requestHeaders : [],
					username : null,
					password : null
	}
	this.callbacks = {onReset : null,
					  onOpen : null,
					  onHeaders : null,
					  onLoad : null,
					  onSuccess : function(){return null;},
					  onFailure : function(){throw new Error("Request failed")}
					  }
}

AjaxRequest.prototype._processResponse = function(_res) {
if (this.request) {
	switch(this.request.readyState) {
		case this.states.OPENED: if (this.callbacks.onOpen != null) eval(this.callbacks.onOpen+"(this.request)");
		                         break;
		case this.states.HEADERS_RECEIVED: if (this.callbacks.onHeaders != null) eval(this.callbacks.onHeaders+"(this.request)");
		                         break;		
		case this.states.LOADING: if (this.callbacks.onLoad != null) eval(this.callbacks.onLoad+"(this.request)");
		                         break;	
		case this.states.DONE: if (this.callbacks.onSuccess != null) eval(this.callbacks.onSuccess+"(this.request)");
		                         break;		
		case this.states.FAILURE: if (this.callbacks.onFailure != null) this.callbacks.onFailure(this.request);
		                         break;									 
	}
	}
}

AjaxRequest.prototype.hasPendingRequest = function() {
	if (this.request.readyState != this.states.UNSENT && this.request.readyState != this.states.DONE) {
		return true;
	} else {
		return false;
	}
}

AjaxRequest.prototype.send = function() {
	this._checkOptions();
	if (!this.hasPendingRequest()) {
		if (this.options.method.toLowerCase() == "get") {
			this._sendGetRequest();
		} else if (this.options.method.toLowerCase() == "post") {
			this._sendPostRequest();
		}
	}
}

AjaxRequest.prototype._sendGetRequest = function() {
	var instance = this;
	var fullUrl = this.url + (this.options.parameters != "" ? "?" + this.options.parameters : "");
	if (this.options.username != null) {
		this.request.open("get", fullUrl, this.options.asynchronous, this.options.username, this.options.password);
	} else {
		this.request.open("get", fullUrl, this.options.asynchronous);
	}
	this._setRequestHeaders();
	this.request.onreadystatechange = function(){instance._processResponse();}
	this.request.send(this.options.parameters);
}

AjaxRequest.prototype._setRequestHeaders = function() {
	var headers = this.options.requestHeaders;
	try	{
		for (i = 0; i < headers.length; i++) {
			this.request.setRequestHeader(headers[i].name, headers[i].value);
		}
	} catch(e) {
		throw new Error("The header has an invalid form");
	}
}

AjaxRequest.prototype._sendPostRequest = function() {
	var instance = this;
	if (this.options.username != null) {
		this.request.open("post", this.url, this.options.asynchronous, this.options.username, this.options.password);
	} else {
		this.request.open("post", this.url, this.options.asynchronous);
	}
	this._setRequestHeaders();
	this._setPostHeaders();		
	this.request.onreadystatechange = function(){instance._processResponse();}
	this.request.send(this.options.parameters);
}

AjaxRequest.prototype._checkOptions = function () {
	if(!this._isValidString(this.url)) {
			throw new Error("The url parameter must be a valid URL");
	}
	try	{
		if(!this.callbacks || !this.callbacks.onSuccess){
			throw new Error("The onSuccess callback function of the options parameter is mandatory");
		}
	} catch(e) {
			throw new Error("Err");
	}	
}

AjaxRequest.prototype._isValidString = function(str) {
		if(!str || typeof str != "string")
		{
			return false;
		}
		return true;
}

AjaxRequest.prototype._setPostHeaders = function() {
    /*
	var postHeaders = [];
	postHeaders.push({name: "Content-type", value: "application/x-www-form-urlencoded"});
	postHeaders.push({name: "Content-length", value: this.options.parameters.length});
	postHeaders.push({name: "Connection", value: "close"});
	this.options.requestHeaders = this.options.requestHeaders.concat(postHeaders);		
	*/
	this.request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	this.request.setRequestHeader("Content-length", this.options.parameters.length);
	this.request.setRequestHeader("Connection", "close");
}

// Misc functions

function getCurrentTimeMillis() {
	var _d = new Date();
	return Date.UTC(_d.getFullYear(), _d.getMonth(), _d.getDate(), _d.getHours(), _d.getMinutes(), _d.getSeconds(), _d.getMilliseconds());
}

// View/Controller objects

function Controller(mod, act, view) {
	this._model = mod;
	this._actions = act;
	this._view = view;
}

Controller.prototype.executeAction = function(act) {
	functionToCall = eval("this._actions."+act);
	eval(functionToCall+"(this._model)");
	this._view.render();
}

function View(mod, bnd) {
	this._model = mod;
	this._binds = bnd;
}

View.prototype.render = function() {
	for (var props in this._binds) {
		fieldToUpdate = eval("this._binds."+props);
		valueToUpdate = eval("this._model."+props);
		if (typeof valueToUpdate == "string") {
			eval(fieldToUpdate+"=\""+valueToUpdate+"\"");
		} else {		
			eval(fieldToUpdate+"="+valueToUpdate);
		}
	}
}

function get_html_translation_table(table, quote_style) {
    var entities = {}, histogram = {}, decimal = 0, symbol = '';
    var constMappingTable = {}, constMappingQuoteStyle = {};
    var useTable = {}, useQuoteStyle = {};
    useTable      = (table ? table.toUpperCase() : 'HTML_SPECIALCHARS');
    useQuoteStyle = (quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT');
    constMappingTable[0]      = 'HTML_SPECIALCHARS';
    constMappingTable[1]      = 'HTML_ENTITIES';
    constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
    constMappingQuoteStyle[2] = 'ENT_COMPAT';
    constMappingQuoteStyle[3] = 'ENT_QUOTES';
    if (!isNaN(useTable)) {
        useTable = constMappingTable[useTable];
    }
    if (!isNaN(useQuoteStyle)) {
        useQuoteStyle = constMappingQuoteStyle[useQuoteStyle];
    }
    if (useQuoteStyle != 'ENT_NOQUOTES') {
        entities['34'] = '&quot;';
    }
    if (useQuoteStyle == 'ENT_QUOTES') {
        entities['39'] = '&#039;';
    }
    if (useTable == 'HTML_SPECIALCHARS') {
        entities['38'] = '&amp;';
        entities['60'] = '&lt;';
        entities['62'] = '&gt;';
    } else if (useTable == 'HTML_ENTITIES') {
	    entities['38']  = '&amp;';
	    entities['60']  = '&lt;';
	    entities['62']  = '&gt;';
	    entities['160'] = '&nbsp;';
	    entities['161'] = '&iexcl;';
	    entities['162'] = '&cent;';
	    entities['163'] = '&pound;';
	    entities['164'] = '&curren;';
	    entities['165'] = '&yen;';
	    entities['166'] = '&brvbar;';
	    entities['167'] = '&sect;';
	    entities['168'] = '&uml;';
	    entities['169'] = '&copy;';
	    entities['170'] = '&ordf;';
	    entities['171'] = '&laquo;';
	    entities['172'] = '&not;';
	    entities['173'] = '&shy;';
	    entities['174'] = '&reg;';
	    entities['175'] = '&macr;';
	    entities['176'] = '&deg;';
	    entities['177'] = '&plusmn;';
	    entities['178'] = '&sup2;';
	    entities['179'] = '&sup3;';
	    entities['180'] = '&acute;';
	    entities['181'] = '&micro;';
	    entities['182'] = '&para;';
	    entities['183'] = '&middot;';
	    entities['184'] = '&cedil;';
	    entities['185'] = '&sup1;';
	    entities['186'] = '&ordm;';
	    entities['187'] = '&raquo;';
	    entities['188'] = '&frac14;';
	    entities['189'] = '&frac12;';
	    entities['190'] = '&frac34;';
	    entities['191'] = '&iquest;';
	    entities['192'] = '&Agrave;';
	    entities['193'] = '&Aacute;';
	    entities['194'] = '&Acirc;';
	    entities['195'] = '&Atilde;';
	    entities['196'] = '&Auml;';
	    entities['197'] = '&Aring;';
	    entities['198'] = '&AElig;';
	    entities['199'] = '&Ccedil;';
	    entities['200'] = '&Egrave;';
	    entities['201'] = '&Eacute;';
	    entities['202'] = '&Ecirc;';
	    entities['203'] = '&Euml;';
	    entities['204'] = '&Igrave;';
	    entities['205'] = '&Iacute;';
	    entities['206'] = '&Icirc;';
	    entities['207'] = '&Iuml;';
	    entities['208'] = '&ETH;';
	    entities['209'] = '&Ntilde;';
	    entities['210'] = '&Ograve;';
	    entities['211'] = '&Oacute;';
	    entities['212'] = '&Ocirc;';
	    entities['213'] = '&Otilde;';
	    entities['214'] = '&Ouml;';
	    entities['215'] = '&times;';
	    entities['216'] = '&Oslash;';
	    entities['217'] = '&Ugrave;';
	    entities['218'] = '&Uacute;';
	    entities['219'] = '&Ucirc;';
	    entities['220'] = '&Uuml;';
	    entities['221'] = '&Yacute;';
	    entities['222'] = '&THORN;';
	    entities['223'] = '&szlig;';
	    entities['224'] = '&agrave;';
	    entities['225'] = '&aacute;';
	    entities['226'] = '&acirc;';
	    entities['227'] = '&atilde;';
	    entities['228'] = '&auml;';
	    entities['229'] = '&aring;';
	    entities['230'] = '&aelig;';
	    entities['231'] = '&ccedil;';
	    entities['232'] = '&egrave;';
	    entities['233'] = '&eacute;';
	    entities['234'] = '&ecirc;';
	    entities['235'] = '&euml;';
	    entities['236'] = '&igrave;';
	    entities['237'] = '&iacute;';
	    entities['238'] = '&icirc;';
	    entities['239'] = '&iuml;';
	    entities['240'] = '&eth;';
	    entities['241'] = '&ntilde;';
	    entities['242'] = '&ograve;';
	    entities['243'] = '&oacute;';
	    entities['244'] = '&ocirc;';
	    entities['245'] = '&otilde;';
	    entities['246'] = '&ouml;';
	    entities['247'] = '&divide;';
	    entities['248'] = '&oslash;';
	    entities['249'] = '&ugrave;';
	    entities['250'] = '&uacute;';
	    entities['251'] = '&ucirc;';
	    entities['252'] = '&uuml;';
	    entities['253'] = '&yacute;';
	    entities['254'] = '&thorn;';
	    entities['255'] = '&yuml;';
    } else {
        throw Error("Table: "+useTable+' not supported');
        return false;
    }
    for (decimal in entities) {
        symbol = String.fromCharCode(decimal);
        histogram[symbol] = entities[decimal];
    }
    
    return histogram;
}

function html_entity_decode( string, quote_style ) {
    var histogram = {}, symbol = '', tmp_str = '', entity = '';
    tmp_str = string.toString();
    if (false === (histogram = get_html_translation_table('HTML_ENTITIES', quote_style))) {
        return false;
    }
    delete(histogram['&']);
    histogram['&'] = '&amp;';
    for (symbol in histogram) {
        entity = histogram[symbol];
        tmp_str = tmp_str.split(entity).join(symbol);
    }
    return tmp_str;
}

function htmlentities (string, quote_style) {
    var histogram = {}, symbol = '', tmp_str = '', entity = '';
    tmp_str = string.toString();
    if (false === (histogram = get_html_translation_table('HTML_ENTITIES', quote_style))) {
        return false;
    }
    for (symbol in histogram) {
        entity = histogram[symbol];
        tmp_str = tmp_str.split(symbol).join(entity);
    }
    return tmp_str;
}

function specialCharsToHtml(toEncode) {
	return htmlentities(toEncode, "ENT_NOQUOTES");
}

function htmlToSpecialChars(toDecode) {
	return html_entity_decode(toDecode, "ENT_NOQUOTES");
}


