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) { 
AjaxRequest.submit = function(url, args) { 
var myRequest = new AjaxRequest(); 
if (myRequest==null) { return false; } 
//var serializedForm = AjaxRequest.serializeForm(theform); 
//myRequest.method = theform.method.toUpperCase(); 
myRequest.method = 'POST'; 
//myRequest.url = theform.action; 
myRequest.url = url;
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; 