function trim(str)
{
	var ereg	= new RegExp("^( )+");
	str	= str.replace(ereg,"");
	ereg	= new RegExp("( )+$");
	str	= str.replace(ereg,"");
	return str;
}

function chkChangeTitle(obj)
{
	obj.title.value	= trim(obj.title.value);

	if(obj.title.value == '')
	{
		obj.title.focus();
		return false;
	}

	if(!confirm("Ã¥ÀÓÁú ¼ö ÀÖ°ÚÀ½?"))
	{
		alert("-_,-;; ±×·¸´Ù°í ÂÌ±â´Â...");
		return false;
	}
}

function openChangeForm()
{
	document.getElementById('changeTitle').style.display	= 'inline';

	try
	{
		document.ctitle.title.select();
	}
	catch(e)
	{

	}
}

function ereg(exp, str)
{
	exp = new RegExp(exp);
	exp = str.match(exp);

	return exp;
}

function eregi_replace(ereg, dest, str)
{
	ereg = eval("/"+ereg+"/gim");
	return str.replace(ereg, dest);
}

function setCookie(name, value, day)
{
	var exp	= '';

	if(day > 0)
	{
		var today= new Date();
		today.setDate(today.getDate() + day);
		exp	= " expires=" + today.toGMTString() + ";";
	}

	document.cookie = name + "=" + escape(value) + "; path=/;" + exp + ";"
}

var lastAlramHour	= false;

function show(timeGap)
{
	if(timeGap == 'e')
	{
		document.getElementById('time_area').innerHTML	= "<font style=\"font-size:20pt; letter-spacing:-2px; color:#000000; font-weight:bold\">¼­¹ö°¡ ½Ã°£À» ¾È¾Ë·ÁÁÖ³×¿ä . . . ¸Å¿ì ÁË¼Û ; ; ¾Æ³ö ; ;<br>¸±·º½º ÇÏ½Ã°í Àá½Ã ÈÄ¿¡ ´Ù½Ã ÇÑ ¹ø µµÀüÇØº¾½Ã´Ù</font><br><br>";
		return;
	}

	var thisTime	= timeGap + time();

	try
	{
		var gmtValue	= document.getElementById('gmt').value;

		if(ereg("^p", gmtValue))
		{
			gmtValue	= parseInt(eregi_replace("[^0-9]", "", gmtValue), 10);
			gmtValue	-= 540;
			thisTime	+= gmtValue * 60;
		}
		else if(ereg("^m", gmtValue))
		{
			gmtValue	= parseInt(eregi_replace("[^0-9]", "", gmtValue), 10);
			gmtValue	+= 540;
			thisTime	-= gmtValue * 60;
		}
	}
	catch(e)
	{

	}

	var t	= date('Y/m/d/H/i/s', thisTime).split("/");

	if(t[4] == '29' || t[4] == '59')
	{
		document.getElementById('time_area').innerHTML	= "<font color=#cc0000>" + t[0] + "³â " + t[1] + "¿ù " + t[2] + "ÀÏ " + t[3] + "½Ã " + t[4] + "ºÐ " + t[5] + "ÃÊ</font>";
	}
	else
	{
		document.getElementById('time_area').innerHTML	= t[0] + "³â " + t[1] + "¿ù " + t[2] + "ÀÏ " + t[3] + "½Ã " + t[4] + "ºÐ " + t[5] + "ÃÊ";
	}

	if((t[4] == '59' || t[4] == '29') && (t[5] == '50' || t[5] == '51'))
	{
		try
		{
			document.getElementById('resultButton').style.display	= 'inline';
		}
		catch(e)
		{

		}
	}

	if((t[4] == '15' || t[4] == '45') && (t[5] == '00' || t[5] == '01'))
	{
		try
		{
			document.getElementById('resultButton').style.display	= 'none';
		}
		catch(e)
		{

		}
	}

	setTimeout("show(" + timeGap + ")", 1000);

	if(document.getElementById('playAlram').checked && (t[4] == '29' || t[4] == '59') && t[5] == '51' && lastAlramHour != t[3] + t[4])
	{
		try
		{
			document.getElementById('soundControl').playVoice('clock.mp3');
		}
		catch(e)
		{

		}

		lastAlramHour	= t[3] + t[4];
	}
}

function checkConnect()
{
	AjaxGet("./ing.php?mode=checkConnect&host=" + host, checkConnectOk);
}

function checkConnectOk(s)
{
	s	= s.split("\n");
	var buff	= '<b>ÇöÀç Á¢¼ÓÀÚµéÀÌ È®ÀÎÁßÀÎ °÷... ÇÔ²² ÇÏ°í ½ÍÀ¸¸é Å¬¸¯~</b><br><img src="./blank.gif" width=5 height=10 border=0><br>';

	if(s[0])
	{
		var res	= s[0].split('`');

		try
		{
			document.getElementById('resultAreaBox').style.display	= 'inline';

			document.getElementById('resultAreaS').innerHTML	= ' success ' + res[1] + ' (' + res[3] + '%)';
			document.getElementById('resultAreaF').innerHTML	= ' failure ' + res[2] + ' (' + res[4] + '%)';

			document.getElementById('resultAreaSgraph').style.width	= res[3] + '%';
			document.getElementById('resultAreaFgraph').style.width	= res[4] + '%';
		}
		catch(e)
		{

		}
	}
	else
	{
		document.getElementById('resultAreaBox').style.display	= 'none';
	}



	for(var i=1; i<s.length; i++)
	{
		if(i == 20)	break;

		var l	= s[i].split("`");
		var f	= 9;

		if(i == 0 && l[2]>1)	f	= 28;
		if(i == 1 && l[2]>1)	f	= 24;
		if(i == 2 && l[2]>1)	f	= 20;
		if(i == 3 && l[2]>1)	f	= 15;

		buff	+= "<a href='./?host=" + l[0] + "' style='color:#FF754B; font-size:" + f + "pt; letter-spacing:-1px' title='¼­¹ö½Ã°£ È®ÀÎÇÏ±â'>";
		buff	+= "<b>" + l[1] + " (" + l[2] + ")</b>";

		if(l[0])
		{
			buff += " <font style='font-size:9pt'>(" + l[0] + ")</font>";
		}

		buff	+= "</a> <span style='cursor:pointer; font-size:8pt' title='Àü¿ë Ã¤ÆÃ¹æÀ¸·Î ÀÔÀå' onclick=\"openChatWindow('" + l[0] + "')\"><u>chat</u></span><br><img src='./blank.gif' width=5 height=5 border=0><br>";
	}

	document.getElementById('dash').innerHTML	= buff;

	setTimeout("checkConnect()", 60000);
}

function openChatWindow(id)
{
	var w	= 540;
	var h	= 460;

	var lis	= screen.width / 2 - w / 2;
	var tis	= screen.height / 2 - h / 2;
	var win;

	window.open("./chat.php?id=" + id, "serverTimeChat", 'resizable=yes, scrollbars=yes, width=' + w + ', height=' + h + ', top=' + tis + ', left=' + lis);
}


var chatStatus	= true;

function chatControl()
{
	if(chatStatus == true)
	{
		document.getElementById('flashChat').style.height='0px';
		document.getElementById('chatControlButton').innerHTML	= 'Ã¤ÆÃÄÑ±â';
		chatStatus = false;
	}
	else
	{
		document.getElementById('flashChat').style.height='428px';
		document.getElementById('chatControlButton').innerHTML	= 'Ã¤ÆÃ²ô±â';
		chatStatus = true;
	}
}


var commentSubmited	= false;

function chkCom(obj)
{
	if(commentSubmited == true)	return false;
	if(!obj.memo.value || commentFormReset == false)
	{
		obj.memo.focus();
		return false;
	}

	commentSubmited = true;
}


var setGradient=(function(){var p_dCanvas=document.createElement("canvas");var p_useCanvas=!!(typeof (p_dCanvas.getContext)=="function");var p_dCtx=p_useCanvas?p_dCanvas.getContext("2d"):null;var p_isIE=
/*@cc_on!@*/
false;try{p_dCtx.canvas.toDataURL();}catch(err){p_useCanvas=false;}if(p_useCanvas){return function(dEl,sColor1,sColor2,bRepeatY){if(typeof (dEl)=="string"){dEl=document.getElementById(dEl);}if(!dEl){return false;}var nW=dEl.offsetWidth;var nH=dEl.offsetHeight;p_dCanvas.width=nW;p_dCanvas.height=nH;var dGradient;var sRepeat;if(bRepeatY){dGradient=p_dCtx.createLinearGradient(0,0,nW,0);sRepeat="repeat-y";}else{dGradient=p_dCtx.createLinearGradient(0,0,0,nH);sRepeat="repeat-x";}dGradient.addColorStop(0,sColor1);dGradient.addColorStop(1,sColor2);p_dCtx.fillStyle=dGradient;p_dCtx.fillRect(0,0,nW,nH);var sDataUrl=p_dCtx.canvas.toDataURL("image/png");with(dEl.style){backgroundRepeat=sRepeat;backgroundImage="url("+sDataUrl+")";backgroundColor=sColor2;}};}else{if(p_isIE){p_dCanvas=p_useCanvas=p_dCtx=null;return function(dEl,sColor1,sColor2,bRepeatY){if(typeof (dEl)=="string"){dEl=document.getElementById(dEl);}if(!dEl){return false;}dEl.style.zoom=1;var sF=dEl.currentStyle.filter;dEl.style.filter+=" "+["progid:DXImageTransform.Microsoft.gradient(	GradientType=",+(!!bRepeatY),",enabled=true,startColorstr=",sColor1,", endColorstr=",sColor2,")"].join("");};}else{p_dCanvas=p_useCanvas=p_dCtx=null;return function(dEl,sColor1,sColor2){if(typeof (dEl)=="string"){dEl=document.getElementById(dEl);}if(!dEl){return false;}with(dEl.style){backgroundColor=sColor2;}};}}})();

function time()
{
    // http://kevin.vanzonneveld.net
    // +   original by: GeekFG (http://geekfg.blogspot.com)
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: metjay
    // *     example 1: timeStamp = time();
    // *     results 1: timeStamp > 1000000000 && timeStamp < 2000000000

    return Math.round(new Date().getTime()/1000);
}

function date ( format, timestamp )
{
    // http://kevin.vanzonneveld.net
    // +   original by: Carlos R. L. Rodrigues (http://www.jsfromhell.com)
    // +      parts by: Peter-Paul Koch (http://www.quirksmode.org/js/beat.html)
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: MeEtc (http://yass.meetcweb.com)
    // +   improved by: Brad Touesnard
    // +   improved by: Tim Wiel
    // +   improved by: Bryan Elliott
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +   improved by: David Randall
    // +      input by: Brett Zamir (http://brett-zamir.me)
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +   derived from: gettimeofday
    // %        note 1: Uses global: php_js to store the default timezone
    // *     example 1: date('H:m:s \\m \\i\\s \\m\\o\\n\\t\\h', 1062402400);
    // *     returns 1: '09:09:40 m is month'
    // *     example 2: date('F j, Y, g:i a', 1062462400);
    // *     returns 2: 'September 2, 2003, 2:26 am'
    // *     example 3: date('Y W o', 1062462400);
    // *     returns 3: '2003 36 2003'
    // *     example 4: x = date('Y m d', (new Date()).getTime()/1000); // 2009 01 09
    // *     example 4: (x+'').length == 10
    // *     returns 4: true

    var jsdate=(
        (typeof(timestamp) == 'undefined') ? new Date() : // Not provided
        (typeof(timestamp) == 'number') ? new Date(timestamp*1000) : // UNIX timestamp
        new Date(timestamp) // Javascript Date()
    ); // , tal=[]
    var pad = function(n, c){
        if( (n = n + "").length < c ) {
            return new Array(++c - n.length).join("0") + n;
        } else {
            return n;
        }
    };
    var _dst = function (t) {
        // Calculate Daylight Saving Time (derived from gettimeofday() code)
        var dst=0;
        var jan1 = new Date(t.getFullYear(), 0, 1, 0, 0, 0, 0);  // jan 1st
        var june1 = new Date(t.getFullYear(), 6, 1, 0, 0, 0, 0); // june 1st
        var temp = jan1.toUTCString();
        var jan2 = new Date(temp.slice(0, temp.lastIndexOf(' ')-1));
        temp = june1.toUTCString();
        var june2 = new Date(temp.slice(0, temp.lastIndexOf(' ')-1));
        var std_time_offset = (jan1 - jan2) / (1000 * 60 * 60);
        var daylight_time_offset = (june1 - june2) / (1000 * 60 * 60);

        if (std_time_offset === daylight_time_offset) {
            dst = 0; // daylight savings time is NOT observed
        }
        else {
            // positive is southern, negative is northern hemisphere
            var hemisphere = std_time_offset - daylight_time_offset;
            if (hemisphere >= 0) {
                std_time_offset = daylight_time_offset;
            }
            dst = 1; // daylight savings time is observed
        }
        return dst;
    };
    var ret = '';
    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(){
                var 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;
                }
                if(a <= 2 && nd >= 4 && a >= (6 - nd)){
                    nd2 = new Date(jsdate.getFullYear() - 1 + "/12/31");
                    return date("W", Math.round(nd2.getTime()/1000));
                }
                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(){
                var 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();
                }
                if( n & 1 && n < 8 || !(n & 1) && n > 7 ){
                    return 31;
                }
                return 30;
            },

        // Year
            L: function(){
                var y = f.Y();
                return (!(y & 3) && (y % 1e2 || !(y % 4e2))) ? 1 : 0;
            },
            o: function(){
                if (f.n() === 12 && f.W() === 1) {
                    return jsdate.getFullYear()+1;
                }
                if (f.n() === 1 && f.W() >= 52) {
                    return jsdate.getFullYear()-1;
                }
                return jsdate.getFullYear();
            },
            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: function(){
                return pad(jsdate.getMilliseconds()*1000, 6);
            },

        // Timezone
            e: function () {
/*                var abbr='', i=0;
                if (this.php_js && this.php_js.default_timezone) {
                    return this.php_js.default_timezone;
                }
                if (!tal.length) {
                    tal = timezone_abbreviations_list();
                }
                for (abbr in tal) {
                    for (i=0; i < tal[abbr].length; i++) {
                        if (tal[abbr][i].offset === -jsdate.getTimezoneOffset()*60) {
                            return tal[abbr][i].timezone_id;
                        }
                    }
                }
*/
                return 'UTC';
            },
            I: function(){
                return _dst(jsdate);
            },
            O: function(){
               var t = pad(Math.abs(jsdate.getTimezoneOffset()/60*100), 4);
               t = (jsdate.getTimezoneOffset() > 0) ? "-"+t : "+"+t;
               return t;
            },
            P: function(){
                var O = f.O();
                return (O.substr(0, 3) + ":" + O.substr(3, 2));
            },
            T: function () {
/*                var abbr='', i=0;
                if (!tal.length) {
                    tal = timezone_abbreviations_list();
                }
                if (this.php_js && this.php_js.default_timezone) {
                    for (abbr in tal) {
                        for (i=0; i < tal[abbr].length; i++) {
                            if (tal[abbr][i].timezone_id === this.php_js.default_timezone) {
                                return abbr.toUpperCase();
                            }
                        }
                    }
                }
                for (abbr in tal) {
                    for (i=0; i < tal[abbr].length; i++) {
                        if (tal[abbr][i].offset === -jsdate.getTimezoneOffset()*60) {
                            return abbr.toUpperCase();
                        }
                    }
                }
*/
                return 'UTC';
            },
            Z: function(){
               return -jsdate.getTimezoneOffset()*60;
            },

        // Full Date/Time
            c: function(){
                return f.Y() + "-" + f.m() + "-" + f.d() + "T" + f.h() + ":" + f.i() + ":" + f.s() + f.P();
            },
            r: function(){
                return f.D()+', '+f.d()+' '+f.M()+' '+f.Y()+' '+f.H()+':'+f.i()+':'+f.s()+' '+f.O();
            },
            U: function(){
                return Math.round(jsdate.getTime()/1000);
            }
    };

    return format.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;
    });
}

// ===================================================================
// Author: Matt Kruse <matt@ajaxtoolbox.com>
// WWW: http://www.AjaxToolbox.com/
//
// NOTICE: You may use this code for any purpose, commercial or
// private, without any further permission from the author. You may
// remove this notice from your final code if you wish, however it is
// appreciated by the author if at least my web site address is kept.
//
// You may *NOT* re-distribute this code in any way except through its
// use. That means, you can include it in your product, or your web
// site, or any other form where the code is actually being used. You
// may not put the plain javascript up on your site for download or
// include it in your javascript libraries for download.
// If you wish to share this code with others, please just point them
// to the URL instead.
// Please DO NOT link directly to my .js files from your site. Copy
// the files to your server and use them there. Thank you.
// ===================================================================

/**
 * The AjaxRequest class is a wrapper for the XMLHttpRequest objects which
 * are available in most modern browsers. It simplifies the interfaces for
 * making Ajax requests, adds commonly-used convenience methods, and makes
 * the process of handling state changes more intuitive.
 * An object may be instantiated and used, or the Class methods may be used
 * which internally create an AjaxRequest object.
 */
function AjaxRequest() {
	var req = new Object();

	// -------------------
	// Instance properties
	// -------------------

	/**
	 * Timeout period (in ms) until an async request will be aborted, and
	 * the onTimeout function will be called
	 */
	req.timeout = null;

	/**
	 *	Since some browsers cache GET requests via XMLHttpRequest, an
	 * additional parameter called AjaxRequestUniqueId will be added to
	 * the request URI with a unique numeric value appended so that the requested
	 * URL will not be cached.
	 */
	req.generateUniqueUrl = true;

	/**
	 * The url that the request will be made to, which defaults to the current
	 * url of the window
	 */
	req.url = window.location.href;

	/**
	 * The method of the request, either GET (default), POST, or HEAD
	 */
	req.method = "GET";

	/**
	 * Whether or not the request will be asynchronous. In general, synchronous
	 * requests should not be used so this should rarely be changed from true
	 */
	req.async = true;

	/**
	 * The username used to access the URL
	 */
	req.username = null;

	/**
	 * The password used to access the URL
	 */
	req.password = null;

	/**
	 * The parameters is an object holding name/value pairs which will be
	 * added to the url for a GET request or the request content for a POST request
	 */
	req.parameters = new Object();

	/**
	 * The sequential index number of this request, updated internally
	 */
	req.requestIndex = AjaxRequest.numAjaxRequests++;

	/**
	 * Indicates whether a response has been received yet from the server
	 */
	req.responseReceived = false;

	/**
	 * The name of the group that this request belongs to, for activity
	 * monitoring purposes
	 */
	req.groupName = null;

	/**
	 * The query string to be added to the end of a GET request, in proper
	 * URIEncoded format
	 */
	req.queryString = "";

	/**
	 * After a response has been received, this will hold the text contents of
	 * the response - even in case of error
	 */
	req.responseText = null;

	/**
	 * After a response has been received, this will hold the XML content
	 */
	req.responseXML = null;

	/**
	 * After a response has been received, this will hold the status code of
	 * the response as returned by the server.
	 */
	req.status = null;

	/**
	 * After a response has been received, this will hold the text description
	 * of the response code
	 */
	req.statusText = null;

	/**
	 * An internal flag to indicate whether the request has been aborted
	 */
	req.aborted = false;

	/**
	 * The XMLHttpRequest object used internally
	 */
	req.xmlHttpRequest = null;

	// --------------
	// Event handlers
	// --------------

	/**
	 * If a timeout period is set, and it is reached before a response is
	 * received, a function reference assigned to onTimeout will be called
	 */
	req.onTimeout = null;

	/**
	 * A function reference assigned will be called when readyState=1
	 */
	req.onLoading = null;

	/**
	 * A function reference assigned will be called when readyState=2
	 */
	req.onLoaded = null;

	/**
	 * A function reference assigned will be called when readyState=3
	 */
	req.onInteractive = null;

	/**
	 * A function reference assigned will be called when readyState=4
	 */
	req.onComplete = null;

	/**
	 * A function reference assigned will be called after onComplete, if
	 * the statusCode=200
	 */
	req.onSuccess = null;

	/**
	 * A function reference assigned will be called after onComplete, if
	 * the statusCode != 200
	 */
	req.onError = null;

	/**
	 * If this request has a group name, this function reference will be called
	 * and passed the group name if this is the first request in the group to
	 * become active
	 */
	req.onGroupBegin = null;

	/**
	 * If this request has a group name, and this request is the last request
	 * in the group to complete, this function reference will be called
	 */
	req.onGroupEnd = null;

	// Get the XMLHttpRequest object itself
	req.xmlHttpRequest = AjaxRequest.getXmlHttpRequest();
	if (req.xmlHttpRequest==null) { return null; }

	// -------------------------------------------------------
	// Attach the event handlers for the XMLHttpRequest object
	// -------------------------------------------------------
	req.xmlHttpRequest.onreadystatechange =
	function() {
		if (req==null || req.xmlHttpRequest==null) { return; }
		if (req.xmlHttpRequest.readyState==1) { req.onLoadingInternal(req); }
		if (req.xmlHttpRequest.readyState==2) { req.onLoadedInternal(req); }
		if (req.xmlHttpRequest.readyState==3) { req.onInteractiveInternal(req); }
		if (req.xmlHttpRequest.readyState==4) { req.onCompleteInternal(req); }
	};

	// ---------------------------------------------------------------------------
	// Internal event handlers that fire, and in turn fire the user event handlers
	// ---------------------------------------------------------------------------
	// Flags to keep track if each event has been handled, in case of
	// multiple calls (some browsers may call the onreadystatechange
	// multiple times for the same state)
	req.onLoadingInternalHandled = false;
	req.onLoadedInternalHandled = false;
	req.onInteractiveInternalHandled = false;
	req.onCompleteInternalHandled = false;
	req.onLoadingInternal =
		function() {
			if (req.onLoadingInternalHandled) { return; }
			AjaxRequest.numActiveAjaxRequests++;
			if (AjaxRequest.numActiveAjaxRequests==1 && typeof(window['AjaxRequestBegin'])=="function") {
				AjaxRequestBegin();
			}
			if (req.groupName!=null) {
				if (typeof(AjaxRequest.numActiveAjaxGroupRequests[req.groupName])=="undefined") {
					AjaxRequest.numActiveAjaxGroupRequests[req.groupName] = 0;
				}
				AjaxRequest.numActiveAjaxGroupRequests[req.groupName]++;
				if (AjaxRequest.numActiveAjaxGroupRequests[req.groupName]==1 && typeof(req.onGroupBegin)=="function") {
					req.onGroupBegin(req.groupName);
				}
			}
			if (typeof(req.onLoading)=="function") {
				req.onLoading(req);
			}
			req.onLoadingInternalHandled = true;
		};
	req.onLoadedInternal =
		function() {
			if (req.onLoadedInternalHandled) { return; }
			if (typeof(req.onLoaded)=="function") {
				req.onLoaded(req);
			}
			req.onLoadedInternalHandled = true;
		};
	req.onInteractiveInternal =
		function() {
			if (req.onInteractiveInternalHandled) { return; }
			if (typeof(req.onInteractive)=="function") {
				req.onInteractive(req);
			}
			req.onInteractiveInternalHandled = true;
		};
	req.onCompleteInternal =
		function() {
			if (req.onCompleteInternalHandled || req.aborted) { return; }
			req.onCompleteInternalHandled = true;
			AjaxRequest.numActiveAjaxRequests--;
			if (AjaxRequest.numActiveAjaxRequests==0 && typeof(window['AjaxRequestEnd'])=="function") {
				AjaxRequestEnd(req.groupName);
			}
			if (req.groupName!=null) {
				AjaxRequest.numActiveAjaxGroupRequests[req.groupName]--;
				if (AjaxRequest.numActiveAjaxGroupRequests[req.groupName]==0 && typeof(req.onGroupEnd)=="function") {
					req.onGroupEnd(req.groupName);
				}
			}
			req.responseReceived = true;
			req.status = req.xmlHttpRequest.status;
			req.statusText = req.xmlHttpRequest.statusText;
			req.responseText = req.xmlHttpRequest.responseText;
			req.responseXML = req.xmlHttpRequest.responseXML;
			if (typeof(req.onComplete)=="function") {
				req.onComplete(req);
			}
			if (req.xmlHttpRequest.status==200 && typeof(req.onSuccess)=="function") {
				req.onSuccess(req);
			}
			else if (typeof(req.onError)=="function") {
				req.onError(req);
			}

			// Clean up so IE doesn't leak memory
			delete req.xmlHttpRequest['onreadystatechange'];
			req.xmlHttpRequest = null;
		};
	req.onTimeoutInternal =
		function() {
			if (req!=null && req.xmlHttpRequest!=null && !req.onCompleteInternalHandled) {
				req.aborted = true;
				req.xmlHttpRequest.abort();
				AjaxRequest.numActiveAjaxRequests--;
				if (AjaxRequest.numActiveAjaxRequests==0 && typeof(window['AjaxRequestEnd'])=="function") {
					AjaxRequestEnd(req.groupName);
				}
				if (req.groupName!=null) {
					AjaxRequest.numActiveAjaxGroupRequests[req.groupName]--;
					if (AjaxRequest.numActiveAjaxGroupRequests[req.groupName]==0 && typeof(req.onGroupEnd)=="function") {
						req.onGroupEnd(req.groupName);
					}
				}
				if (typeof(req.onTimeout)=="function") {
					req.onTimeout(req);
				}
			// Opera won't fire onreadystatechange after abort, but other browsers do.
			// So we can't rely on the onreadystate function getting called. Clean up here!
			delete req.xmlHttpRequest['onreadystatechange'];
			req.xmlHttpRequest = null;
			}
		};

	// ----------------
	// Instance methods
	// ----------------
	/**
	 * The process method is called to actually make the request. It builds the
	 * querystring for GET requests (the content for POST requests), sets the
	 * appropriate headers if necessary, and calls the
	 * XMLHttpRequest.send() method
	*/
	req.process =
		function() {
			if (req.xmlHttpRequest!=null) {
				// Some logic to get the real request URL
				if (req.generateUniqueUrl && req.method=="GET") {
					req.parameters["AjaxRequestUniqueId"] = new Date().getTime() + "" + req.requestIndex;
				}
				var content = null; // For POST requests, to hold query string
				for (var i in req.parameters) {
					if (req.queryString.length>0) { req.queryString += "&"; }
					req.queryString += encodeURIComponent(i) + "=" + encodeURIComponent(req.parameters[i]);
				}
				if (req.method=="GET") {
					if (req.queryString.length>0) {
						req.url += ((req.url.indexOf("?")>-1)?"&":"?") + req.queryString;
					}
				}
				req.xmlHttpRequest.open(req.method,req.url,req.async,req.username,req.password);
				if (req.method=="POST") {
					if (typeof(req.xmlHttpRequest.setRequestHeader)!="undefined") {
						req.xmlHttpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
					}
					content = req.queryString;
				}
				if (req.timeout>0) {
					setTimeout(req.onTimeoutInternal,req.timeout);
				}
				req.xmlHttpRequest.send(content);
			}
		};

	/**
	 * An internal function to handle an Object argument, which may contain
	 * either AjaxRequest field values or parameter name/values
	 */
	req.handleArguments =
		function(args) {
			for (var i in args) {
				// If the AjaxRequest object doesn't have a property which was passed, treat it as a url parameter
				if (typeof(req[i])=="undefined") {
					req.parameters[i] = args[i];
				}
				else {
					req[i] = args[i];
				}
			}
		};

	/**
	 * Returns the results of XMLHttpRequest.getAllResponseHeaders().
	 * Only available after a response has been returned
	 */
	req.getAllResponseHeaders =
		function() {
			if (req.xmlHttpRequest!=null) {
				if (req.responseReceived) {
					return req.xmlHttpRequest.getAllResponseHeaders();
				}
				//alert("Cannot getAllResponseHeaders because a response has not yet been received");
			}
		};

	/**
	 * Returns the the value of a response header as returned by
	 * XMLHttpRequest,getResponseHeader().
	 * Only available after a response has been returned
	 */
	req.getResponseHeader =
		function(headerName) {
			if (req.xmlHttpRequest!=null) {
				if (req.responseReceived) {
					return req.xmlHttpRequest.getResponseHeader(headerName);
				}
				//alert("Cannot getResponseHeader because a response has not yet been received");
			}
		};

	return req;
}

// ---------------------------------------
// Static methods of the AjaxRequest class
// ---------------------------------------

/**
 * Returns an XMLHttpRequest object, either as a core object or an ActiveX
 * implementation. If an object cannot be instantiated, it will return null;
 */
AjaxRequest.getXmlHttpRequest = function() {
	if (window.XMLHttpRequest) {
		return new XMLHttpRequest();
	}
	else if (window.ActiveXObject) {
		// Based on http://jibbering.com/2002/4/httprequest.html
		/*@cc_on @*/
		/*@if (@_jscript_version >= 5)
		try {
			return new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				return new ActiveXObject("Microsoft.XMLHTTP");
			} catch (E) {
				return null;
			}
		}
		@end @*/
	}
	else {
		return null;
	}
};

/**
 * See if any request is active in the background
 */
AjaxRequest.isActive = function() {
	return (AjaxRequest.numActiveAjaxRequests>0);
};

/**
 * Make a GET request. Pass an object containing parameters and arguments as
 * the second argument.
 * These areguments may be either AjaxRequest properties to set on the request
 * object or name/values to set in the request querystring.
 */
AjaxRequest.get = function(args) {
	AjaxRequest.doRequest("GET",args);
};

/**
 * Make a POST request. Pass an object containing parameters and arguments as
 * the second argument.
 * These areguments may be either AjaxRequest properties to set on the request
 * object or name/values to set in the request querystring.
 */
AjaxRequest.post = function(args) {
	AjaxRequest.doRequest("POST",args);
};

/**
 * The internal method used by the .get() and .post() methods
 */
AjaxRequest.doRequest = function(method,args) {
	if (typeof(args)!="undefined" && args!=null) {
		var myRequest = new AjaxRequest();
		myRequest.method = method;
		myRequest.handleArguments(args);
		myRequest.process();
	}
}	;

/**
 * Submit a form. The requested URL will be the form's ACTION, and the request
 * method will be the form's METHOD.
 * Returns true if the submittal was handled successfully, else false so it
 * can easily be used with an onSubmit event for a form, and fallback to
 * submitting the form normally.
 */
AjaxRequest.submit = function(theform, args) {
	var myRequest = new AjaxRequest();
	if (myRequest==null) { return false; }
	var serializedForm = AjaxRequest.serializeForm(theform);
	myRequest.method = theform.method.toUpperCase();
	myRequest.url = theform.action;
	myRequest.handleArguments(args);
	myRequest.queryString = serializedForm;
	myRequest.process();
	return true;
};

/**
 * Serialize a form into a format which can be sent as a GET string or a POST
 * content.It correctly ignores disabled fields, maintains order of the fields
 * as in the elements[] array. The 'file' input type is not supported, as
 * its content is not available to javascript. This method is used internally
 * by the submit class method.
 */
AjaxRequest.serializeForm = function(theform) {
	var els = theform.elements;
	var len = els.length;
	var queryString = "";
	this.addField =
		function(name,value) {
			if (queryString.length>0) {
				queryString += "&";
			}
			queryString += encodeURIComponent(name) + "=" + encodeURIComponent(value);
		};
	for (var i=0; i<len; i++) {
		var el = els[i];
		if (!el.disabled) {
			switch(el.type) {
				case 'text': case 'password': case 'hidden': case 'textarea':
					this.addField(el.name,el.value);
					break;
				case 'select-one':
					if (el.selectedIndex>=0) {
						this.addField(el.name,el.options[el.selectedIndex].value);
					}
					break;
				case 'select-multiple':
					for (var j=0; j<el.options.length; j++) {
						if (el.options[j].selected) {
							this.addField(el.name,el.options[j].value);
						}
					}
					break;
				case 'checkbox': case 'radio':
					if (el.checked) {
						this.addField(el.name,el.value);
					}
					break;
			}
		}
	}
	return queryString;
};

// -----------------------
// Static Class variables
// -----------------------

/**
 * The number of total AjaxRequest objects currently active and running
 */
AjaxRequest.numActiveAjaxRequests = 0;

/**
 * An object holding the number of active requests for each group
 */
AjaxRequest.numActiveAjaxGroupRequests = new Object();

/**
 * The total number of AjaxRequest objects instantiated
 */
AjaxRequest.numAjaxRequests = 0;

function AjaxGet(url, cb)
{
	AjaxRequest.get(
	{
		'url':url,
		'onSuccess':function(req){ cb(req.responseText); }
	}
	);
}

var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + //all caps
   "abcdefghijklmnopqrstuvwxyz" + //all lowercase
   "0123456789+/="; // all numbers plus +/=

function encode64(inp)
{
 var out = ""; //This is the output
 var chr1, chr2, chr3 = ""; //These are the 3 bytes to be encoded
 var enc1, enc2, enc3, enc4 = ""; //These are the 4 encoded bytes
 var i = 0; //Position counter
 do //Set up the loop here
 {
  chr1 = inp.charCodeAt(i++); //Grab the first byte
  chr2 = inp.charCodeAt(i++); //Grab the second byte
  chr3 = inp.charCodeAt(i++); //Grab the third byte
  //Here is the actual base64 encode part.
  //There really is only one way to do it.
  enc1 = chr1 >> 2;
  enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
  enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
  enc4 = chr3 & 63;
  if (isNaN(chr2))
  {
   enc3 = enc4 = 64;
  }
  else if (isNaN(chr3))
  {
   enc4 = 64;
  }
  //Lets spit out the 4 encoded bytes
  out = out + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) +
  keyStr.charAt(enc4);
  // OK, now clean out the variables used.
  chr1 = chr2 = chr3 = "";
  enc1 = enc2 = enc3 = enc4 = "";
 } while (i < inp.length);
 //And finish off the loop
 //Now return the encoded values.
 return out;
}