function obj_stringify( oT, level )
{
	var r = '';
	
	var level = level || 0;

	var namespace = '';

	for (var i=0; i < level ;i++ )
		namespace += '\t';
	
	for ( var iT in oT)
	{
		if ( oT[iT] == null)
			r += namespace + iT + ': null\n';
		else
		{
			switch ( typeof oT[iT] )
			{
				case 'object': 
					r += namespace + iT + '\n' + obj_stringify( oT[iT], level + 1);
				break;
				case 'function':
					r += namespace + iT + ': function\n';
					break;
				default:
					r += namespace + iT + ': ' + oT[iT] + '\n';
					break;
			
			}
		}
		//alert( iT + ':' + oT[iT] + ' :' + typeof( oT[iT] ) );
	}
	return r;
}

/* function: in_array */
function in_array( strNeedle, arrHaystack )
{
    if ( typeof( arrHaystack ) != 'object' )
		return false;

	for( var strEl in arrHaystack )
		if ( arrHaystack[strEl] == strNeedle )
			return true;
            
	return false ;
}

/* function: in_array */
function array_key_exists( strNeedle, arrHaystack )
{
    if ( typeof( arrHaystack ) != 'object' )
		return false;
            
	return( typeof( arrHaystack[strNeedle] ) != 'undefined' );
}

/* shallow merge array_merge */
function array_merge( arrA, arrB )
{
	arrC = new Array();
	
	for( var strKey in arrA )
		arrC[strKey] = arrA[strKey];

	for( var strKey in arrB )
		arrC[strKey] = arrB[strKey];

	return( arrC );
}

                
function evtCancelAll()
{
    event.returnValue   = false;
	event.cancelBubble  = true;
	return( false );
}



/*
function insertAtCursor(myField, myValue)
{
	//IE support
	if (document.selection) {
		myField.focus();
		sel = document.selection.createRange();
		sel.text = myValue;
	}
	//MOZILLA/NETSCAPE support
	else if (myField.selectionStart || myField.selectionStart == .0.)
	{
		var startPos = myField.selectionStart;
		var endPos = myField.selectionEnd;
		myField.value = myField.value.substring(0, startPos) + myValue + myField.value.substring(endPos, myField.value.length);
	}
	else
	{
		myField.value += myValue;
	}
}
*/

// this function sucks ass and is superinefficient, but hey, it does the trick! ;)
function htmlencode (str)
{
	if ( ! str )
		return '';

	str = str.replace(/&/g, "&amp;");
	str = str.replace(/</g, "&lt;");
	str = str.replace(/>/g, "&gt;");
	str = str.replace(/\x22/g, "&quot;");
	str=str.replace(/\xA0/g, "&nbsp;");
	str=str.replace(/\xA1/g, "&iexcl;");
	str=str.replace(/\xA2/g, "&cent;");
	str=str.replace(/\xA3/g, "&pound;");
	str=str.replace(/\xA4/g, "&curren;");
	str=str.replace(/\xA5/g, "&yen;");
	str=str.replace(/\xA6/g, "&brvbar;");
	str=str.replace(/\xA7/g, "&sect;");
	str=str.replace(/\xA8/g, "&uml;");
	str=str.replace(/\xA9/g, "&copy;");
	str=str.replace(/\xAA/g, "&ordf;");
	str=str.replace(/\xAB/g, "&laquo;");
	str=str.replace(/\xAC/g, "&not;");
	str=str.replace(/\xAD/g, "&shy;");
	str=str.replace(/\xAE/g, "&reg;");
	str=str.replace(/\xAF/g, "&macr;");
	str=str.replace(/\xB0/g, "&deg;");
	str=str.replace(/\xB1/g, "&plusmn;");
	str=str.replace(/\xB2/g, "&sup2;");
	str=str.replace(/\xB3/g, "&sup3;");
	str=str.replace(/\xB4/g, "&acute;");
	str=str.replace(/\xB5/g, "&micro;");
	str=str.replace(/\xB6/g, "&para;");
	str=str.replace(/\xB7/g, "&middot;");
	str=str.replace(/\xB8/g, "&cedil;");
	str=str.replace(/\xB9/g, "&sup1;");
	str=str.replace(/\xBA/g, "&ordm;");
	str=str.replace(/\xBB/g, "&raquo;");
	str=str.replace(/\xBC/g, "&frac14;");
	str=str.replace(/\xBD/g, "&frac12;");
	str=str.replace(/\xBE/g, "&frac34;");
	str=str.replace(/\xBF/g, "&iquest;");
	str=str.replace(/\xC0/g, "&Agrave;");
	str=str.replace(/\xC1/g, "&Aacute;");
	str=str.replace(/\xC2/g, "&Acirc;");
	str=str.replace(/\xC3/g, "&Atilde;");
	str=str.replace(/\xC4/g, "&Auml;");
	str=str.replace(/\xC5/g, "&Aring;");
	str=str.replace(/\xC6/g, "&AElig;");
	str=str.replace(/\xC7/g, "&Ccedil;");
	str=str.replace(/\xC8/g, "&Egrave;");
	str=str.replace(/\xC9/g, "&Eacute;");
	str=str.replace(/\xCA/g, "&Ecirc;");
	str=str.replace(/\xCB/g, "&Euml;");
	str=str.replace(/\xCC/g, "&Igrave;");
	str=str.replace(/\xCD/g, "&Iacute;");
	str=str.replace(/\xCE/g, "&Icirc;");
	str=str.replace(/\xCF/g, "&Iuml;");
	str=str.replace(/\xD0/g, "&ETH;");
	str=str.replace(/\xD1/g, "&Ntilde;");
	str=str.replace(/\xD2/g, "&Ograve;");
	str=str.replace(/\xD3/g, "&Oacute;");
	str=str.replace(/\xD4/g, "&Ocirc;");
	str=str.replace(/\xD5/g, "&Otilde;");
	str=str.replace(/\xD6/g, "&Ouml;");
	str=str.replace(/\xD7/g, "&times;");
	str=str.replace(/\xD8/g, "&Oslash;");
	str=str.replace(/\xD9/g, "&Ugrave;");
	str=str.replace(/\xDA/g, "&Uacute;");
	str=str.replace(/\xDB/g, "&Ucirc;");
	str=str.replace(/\xDC/g, "&Uuml;");
	str=str.replace(/\xDD/g, "&Yacute;");
	str=str.replace(/\xDE/g, "&THORN;");
	str=str.replace(/\xDF/g, "&szlig;");
	str=str.replace(/\xE0/g, "&agrave;");
	str=str.replace(/\xE1/g, "&aacute;");
	str=str.replace(/\xE2/g, "&acirc;");
	str=str.replace(/\xE3/g, "&atilde;");
	str=str.replace(/\xE4/g, "&auml;");
	str=str.replace(/\xE5/g, "&aring;");
	str=str.replace(/\xE6/g, "&aelig;");
	str=str.replace(/\xE7/g, "&ccedil;");
	str=str.replace(/\xE8/g, "&egrave;");
	str=str.replace(/\xE9/g, "&eacute;");
	str=str.replace(/\xEA/g, "&ecirc;");
	str=str.replace(/\xEB/g, "&euml;");
	str=str.replace(/\xEC/g, "&igrave;");
	str=str.replace(/\xED/g, "&iacute;");
	str=str.replace(/\xEE/g, "&icirc;");
	str=str.replace(/\xEF/g, "&iuml;");
	str=str.replace(/\xF0/g, "&eth;");
	str=str.replace(/\xF1/g, "&ntilde;");
	str=str.replace(/\xF2/g, "&ograve;");
	str=str.replace(/\xF3/g, "&oacute;");
	str=str.replace(/\xF4/g, "&ocirc;");
	str=str.replace(/\xF5/g, "&otilde;");
	str=str.replace(/\xF6/g, "&ouml;");
	str=str.replace(/\xF7/g, "&divide;");
	str=str.replace(/\xF8/g, "&oslash;");
	str=str.replace(/\xF9/g, "&ugrave;");
	str=str.replace(/\xFA/g, "&uacute;");
	str=str.replace(/\xFB/g, "&ucirc;");
	str=str.replace(/\xFC/g, "&uuml;");
	str=str.replace(/\xFD/g, "&yacute;");
	str=str.replace(/\xFE/g, "&thorn;");
	str=str.replace(/\xFF/g, "&yuml;");
	str=str.replace(/\x20AC/g, "&euro;");

	return str;
};


function urlencode( sInput )
{
	if ( ! sInput )
		return '';

	// The Javascript escape and unescape functions do not correspond
	// with what browsers actually do...
	var SAFECHARS = "0123456789" +					// Numeric
					"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +	// Alphabetic
					"abcdefghijklmnopqrstuvwxyz" +
					"-_.!~*'()";					// RFC2396 Mark characters
	var HEX = "0123456789ABCDEF";

	var plaintext = sInput;
	var encoded = "";
	for (var i = 0; i < plaintext.length; i++ ) {
		var ch = plaintext.charAt(i);
	    if (ch == " ") {
		    encoded += "+";				// x-www-urlencoded, rather than %20
		} else if (SAFECHARS.indexOf(ch) != -1) {
		    encoded += ch;
		} else {
		    var charCode = ch.charCodeAt(0);
			if (charCode > 255) {
			    alert( "Unicode Character '"
                        + ch
                        + "' cannot be encoded using standard URL encoding.\n" +
				          "(URL encoding only supports 8-bit characters.)\n" +
						  "A space (+) will be substituted." );
				encoded += "+";
			} else {
				encoded += "%";
				encoded += HEX.charAt((charCode >> 4) & 0xF);
				encoded += HEX.charAt(charCode & 0xF);
			}
		}
	} // for

	return( encoded );
}

function urldecode( sInput )
{
	if ( ! sInput )
		return '';
   
   // Replace + with ' '
   // Replace %xx with equivalent character
   // Put [ERROR] in output if %xx is invalid.
   var HEXCHARS = "0123456789ABCDEFabcdef";
   var encoded = sInput;
   var plaintext = "";
   var i = 0;
   while (i < encoded.length) {
       var ch = encoded.charAt(i);
	   if (ch == "+") {
	       plaintext += " ";
		   i++;
	   } else if (ch == "%") {
			if (i < (encoded.length-2)
					&& HEXCHARS.indexOf(encoded.charAt(i+1)) != -1
					&& HEXCHARS.indexOf(encoded.charAt(i+2)) != -1 ) {
				plaintext += unescape( encoded.substr(i,3) );
				i += 3;
			} else {
				alert( 'Bad escape combination near ...' + encoded.substr(i) );
				plaintext += "%[ERROR]";
				i++;
			}
		} else {
		   plaintext += ch;
		   i++;
		}
	} // while
	return( plaintext );
}

function $(element) {
  if (arguments.length > 1) {
	for (var i = 0, elements = [], length = arguments.length; i < length; i++)
	  elements.push($(arguments[i]));
	return elements;
  }
  //if ( Object.isString(element))
	element = document.getElementById(element);

  return element;
}

if( !window.XMLHttpRequest )
{
	XMLHttpRequest = function(){
		try{ return new ActiveXObject("MSXML3.XMLHTTP") }catch(e){}
		try{ return new ActiveXObject("MSXML2.XMLHTTP.3.0") }catch(e){}
		try{ return new ActiveXObject("Msxml2.XMLHTTP") }catch(e){}
		try{ return new ActiveXObject("Microsoft.XMLHTTP") }catch(e){}
		throw new Error("Could not find an XMLHttpRequest alternative.")
	};
}

//-- this is the main xhr-
function ajax(url, vars, callbackFunction, debug)
{
	var request = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("MSXML2.XMLHTTP.3.0");

	//-- support for admin
	if ( typeof url == 'object' && top.baseAdminURL )
	{
		url = top.baseAdminURL + toURL( url );
	}

	request.open('POST', url, true);
	request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // charset=UTF-8;

	request.onreadystatechange = function()
	{
		if (request.readyState == 4 && request.status == 200)
		{
			if (request.responseText)
			{
				if ( debug == true )
				{
					alert( request.responseText );
				}
				//-- decide action for callback
				if ( typeof callbackFunction == "function" )
				{
					//-- direct or anonymous functions
					//try
					//{
						//alert( request.responseText );

						//-- warning: argument is json-string, not object
						callbackFunction( request.responseText );
					//}
					//catch ( objException)
					//{
					//	alert( 'Error handling AJAX-Response\n\nCallback=' + callbackFunction + '\n\n' + request.responseText + '');
					//}
				}
				else 
				{
					//try
					//{
						eval( callbackFunction + '(' + request.responseText +');');
					//}
					//catch ( objException)
					//{
					//	alert( 'Error handling AJAX-Response\n\nCallback=' + callbackFunction + '\n\n' + request.responseText + '');
					//}
				}
			}
		}
	};

	if ( typeof vars == 'object')
		vars = toURL( vars );

	if ( debug )
		alert( vars );

	request.send( vars );
}

/*
	takes an object as argument and formats into an url
	
	eg { "Key": "Value 1", "Key2": { "Key3": "Value 2" } }
	will be formatted into Key=Value+1&Key2[Key3]=Value+2&
*/
function toURL( obj, namespace )
{
	var strPost = '';
	var ns = null;

	for( var key in obj )
	{
		ns = ( namespace ) ?  namespace + '[' + key + ']' : key;

		strPost += ( typeof obj[key] == 'object' ) ? toURL( obj[key], ns ) : ns + '=' + encodeURIComponent( obj[key] ) + '&';
	}

	return strPost;
}



if (!this.JSON) {

    JSON = function () {

        function f(n) {    // Format integers to have at least two digits.
            return n < 10 ? '0' + n : n;
        }

        Date.prototype.toJSON = function () {

// Eventually, this method will be based on the date.toISOString method.

            return this.getUTCFullYear()   + '-' +
                 f(this.getUTCMonth() + 1) + '-' +
                 f(this.getUTCDate())      + 'T' +
                 f(this.getUTCHours())     + ':' +
                 f(this.getUTCMinutes())   + ':' +
                 f(this.getUTCSeconds())   + 'Z';
        };


        var m = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        };

        function stringify(value, whitelist) {
            var a,          // The array holding the partial texts.
                i,          // The loop counter.
                k,          // The member key.
                l,          // Length.
                r = /["\\\x00-\x1f\x7f-\x9f]/g,
                v;          // The member value.

            switch (typeof value) {
            case 'string':

                return r.test(value) ?
                    '"' + value.replace(r, function (a) {
                        var c = m[a];
                        if (c) {
                            return c;
                        }
                        c = a.charCodeAt();
                        return '\\u00' + Math.floor(c / 16).toString(16) +
                                                   (c % 16).toString(16);
                    }) + '"' :
                    '"' + value + '"';

            case 'number':

                return isFinite(value) ? String(value) : 'null';

            case 'boolean':
            case 'null':
                return String(value);

            case 'object':

                if (!value) {
                    return 'null';
                }


                if (typeof value.toJSON === 'function') {
                    return stringify(value.toJSON());
                }
                a = [];
                if (typeof value.length === 'number' &&
                        !(value.propertyIsEnumerable('length'))) {

                    l = value.length;
                    for (i = 0; i < l; i += 1) {
                        a.push(stringify(value[i], whitelist) || 'null');
                    }

                    return '[' + a.join(',') + ']';
                }
                if (whitelist) {

                    l = whitelist.length;
                    for (i = 0; i < l; i += 1) {
                        k = whitelist[i];
                        if (typeof k === 'string') {
                            v = stringify(value[k], whitelist);
                            if (v) {
                                a.push(stringify(k) + ':' + v);
                            }
                        }
                    }
                } else {

                    for (k in value) {
                        if (typeof k === 'string') {
                            v = stringify(value[k], whitelist);
                            if (v) {
                                a.push(stringify(k) + ':' + v);
                            }
                        }
                    }
                }

                return '{' + a.join(',') + '}';
            }
        }

        return {
            stringify: stringify,
            parse: function (text, filter) {
                var j;

                function walk(k, v) {
                    var i, n;
                    if (v && typeof v === 'object') {
                        for (i in v) {
                            if (Object.prototype.hasOwnProperty.apply(v, [i])) {
                                n = walk(i, v[i]);
                                if (n !== undefined) {
                                    v[i] = n;
                                } else {
                                    delete v[i];
                                }
                            }
                        }
                    }
                    return filter(k, v);
                }


                if (/^[\],:{}\s]*$/.test(text.replace(/\\./g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

                    j = eval('(' + text + ')');

                    return typeof filter === 'function' ? walk('', j) : j;
                }

                throw new SyntaxError('parseJSON');
            }
        };
    }();
}
