function ajax() {
	var req = new Object();
	
	req.timeout = null;
	
	
	/**
	 * The url that the request will be made to, which defaults to the current 
	 * url of the window
	 */
	req.ajax_url = window.location.href; //'index.html';
	
	/**
	 * 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 = ajax.numAjaxRequests++;
	
	
	/**
	 * 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 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=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;
	

	// Get the XMLHttpRequest object itself
	req.xmlHttpRequest = ajax.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==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.onCompleteInternalHandled = false;
	req.onCompleteInternal = 
		function() 
		{
			if (req.onCompleteInternalHandled || req.aborted) { return; }
			req.onCompleteInternalHandled = true;
			req.status = req.xmlHttpRequest.status;
			req.statusText = req.xmlHttpRequest.statusText;
			req.responseText = req.xmlHttpRequest.responseText;
			if (typeof(req.onComplete)=="function") {
				req.onComplete(req);
			}
			if (req.xmlHttpRequest.status==200 && typeof(req.onSuccess)=="function") 
			{
				req.onSuccess(req.responseText,req.requestIndex);
			}
			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();
				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
				var content = null; // For POST requests, to hold query string
				for (var i in req.parameters) 
//				for (var i = 0; i < req.parameters.length; i++)
				{
					if (req.queryString.length>0) { req.queryString += "&"; }
					for (var p in req.parameters[i])
						req.queryString += encodeURIComponent(p) + "=" + encodeURIComponent(req.parameters[i][p]);
				}
				req.xmlHttpRequest.open('POST',req.ajax_url,true);
				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) 
			{
				for (var p in args[i])
				{
					// If the AjaxRequest object doesn't have a property which was passed, treat it as a url parameter
					if (typeof(req[p])=="undefined") {
						req.parameters[i] = args[i];
					}
					else {
						req[p] = args[i][p];
					}
				}
			}
		};


	

	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;
 */
ajax.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;
	}
};

ajax.post = function(args) 
{
	if (typeof(args)!="undefined" && args!=null) 
	{
		var myRequest = new ajax();
		myRequest.handleArguments(args);
		myRequest.process();
	}
	return myRequest.requestIndex;
};


ajax.numAjaxRequests = 0;


