function xhr() {

	function createXMLHttp() {

		var xmlhttp = false;

		if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
			try {
				xmlhttp = new XMLHttpRequest();
			} catch (e) {
				xmlhttp = false;
			}
		}

		if (!xmlhttp) {
			/*@cc_on @*/
			/*@if (@_jscript_version >= 5)
			// JScript gives us Conditional compilation, we can cope with old IE versions.
			// and security blocked creation of the objects.
			try {
				xmlhttp = new ActiveXObject('MSXML2.XMLHttp.5.0');
			} catch (e) {
				try {
					xmlhttp = new ActiveXObject('MSXML2.XMLHttp.4.0');
				} catch (e) {
					try {
						xmlhttp = new ActiveXObject('MSXML2.XMLHttp.3.0');
					} catch (e) {
						try {
							xmlhttp = new ActiveXObject('MSXML2.XMLHttp');
						} catch (e) {
							try {
								xmlhttp = new ActiveXObject('Microsoft.XMLHttp');
							} catch (e) {
								xmlhttp = false;
							}
						}
					}
				}
			}
			@end @*/
		}

		if (!xmlhttp && window.createRequest) {
			try {
				xmlhttp = window.createRequest(); //used by IceBrowser
			} catch (e) {
				xmlhttp = false;
			}
		}

		if (!xmlhttp) {
			throw new Error("XMLHttp object could be created.");
		};

		return xmlhttp;

	} // end createXMLHttp()


	function fnBindCallback(pResp) {

//alert(oxmlhttp.readyState+'\n'+bComplete+'\n'+sMode);

		var resp = '';

		if (oxmlhttp.readyState == 4 && !bComplete) {
			bComplete = true;
			if (oxmlhttp.status == 200) {

				//alert(oxmlhttp.getAllResponseHeaders());
				//alert(oxmlhttp.getResponseHeader("Content-Type"));
				//alert(oxmlhttp.responseText);
				//alert(oxmlhttp.responseXML);

				var sContentType = oxmlhttp.getResponseHeader("Content-Type");

				if (sContentType == "text/xml") {
					//alert("XML content received.");

					resp  = oxmlhttp.responseXML.documentElement;

				} else if (sContentType == "text/plain" || sContentType == "text/html") {
					//alert("Plain or HTML text content received.");

					resp = oxmlhttp.responseText;

				} else {
					//alert("Other type of content received.");
					resp = oxmlhttp.responseText;
				}

				//fnCallback(oxmlhttp);

				//if mode = async process the result via the callback function
				//if mode = sync the result is set in the response.value property
				if (sMode == 'async') {
					fnCallback(resp);
				} else {
					pResp.value = resp;
				}

			} else {
				alert('There was a problem retrieving the data:\n' + oxmlhttp.status + ":\t" + oxmlhttp.statusText + "\n" + oxmlhttp.responseText);
			}
		}
	} // end callback


	function fnListNv(objlist) {

		//return the name value pairs for selected values of the list object

		var ret = '';

		for (var i = 0; i < objlist.options.length; i++) {
			if (objlist[i].selected) {
				ret += '&' + objlist.name + '=' + escape(objlist[i].value);
			}
		}

		return ret;
	}


	function fnFormNv(theform) { 

		//build name value pairs from the form e.g. aaa=123&bbb=987
		//only consider elements with a name.

		var qs = '';

		for (var e = 0; e < theform.elements.length; e++) { 

			var en = theform.elements[e].name;
			var et = theform.elements[e].type;

			if (en != '') {

				if (et == 'text' || et == 'hidden' || et == 'password' || et == 'textarea') { 

					qs += '&' + en + '=' + escape(theform.elements[e].value);

				} else if (et.substr(0,6) == 'select') {

					qs += fnListNv(theform.elements[e]);

				} else if (et == 'checkbox') {

					qs += '&' + en + '=' + (theform.elements[e].checked?escape(theform.elements[e].value):'');

				}
			}
		} 
		return qs.substr(1);
	} 


  var oxmlhttp   = null;
  var bComplete  = false;
  var fnCallback = null;
	var sMode      = null;

	oxmlhttp = createXMLHttp();
	
  if (!oxmlhttp) {
		alert('Can not perform XMLHttpRequest, you must update your browser to run this application.');
  	return null;
  }

	this.response = function () {
		this.value = '';
	}

	//connect, send and return request

	this.connect = function(sURL,sMethod,sAsync,sVars,fnDone) {
		
		//sAsync: asynch = asynch, sync = sync

    if (!oxmlhttp) return false;

    var sMethod = sMethod.toUpperCase();
    var bAsync  = sAsync=='async'?true:false;
    fnCallback  = fnDone;
    sMode       = sAsync;

    try {
      if (sMethod == "GET")
      {
        oxmlhttp.open(sMethod, sURL+"?"+sVars, bAsync);
        sVars = "";
      }
      else
      {
        oxmlhttp.open(sMethod, sURL, bAsync);
        oxmlhttp.setRequestHeader("Method", "POST "+sURL+" HTTP/1.1");
        oxmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
      }
      
      if (sAsync == 'async') {
				oxmlhttp.onreadystatechange = fnBindCallback;
      }

      oxmlhttp.send(sVars);

      if (sAsync != 'async') {
				fnBindCallback(this.response);
      }

    }
    catch(z) { return false; }
    return true;
	}



	this.connectform = function(oForm,sFormAsync,fnFormDone) {

		//get url, method and vars from the form
		
		var sFormURL    = oForm.action;
		var sFormMethod = oForm.method;
		var nv   = '';
		
		//build name value pairs from the form
		nv = fnFormNv(oForm);
		
		//alert(nv);
		
		return this.connect(sFormURL,sFormMethod,sFormAsync,nv,fnFormDone);

	}



	this.connectarray = function(sArrayURL,sArrayMethod,sArrayAsync,aArrayVars,fnArrayDone) {

		var nv = '';
		
		//build name value pairs from the array

		for (var e = 0; e < aArrayVars.length; e++) { 

			var en = aArrayVars[e][0];
			var ev = aArrayVars[e][1];

			//alert('name:'+en+' value:'+ev);

			if (en != '') {
				nv += (nv == '')?'':'&';

				//set name=value
				nv += en + '=' + escape(ev);
			}
		} 

		return this.connect(sArrayURL,sArrayMethod,sArrayAsync,nv,fnArrayDone);

	}

  return this;

} //end xhr()



/*
//===== USING NEW XMLHTTPREQUEST FUNCTION =====

//initialize xhr (if xhr() isn't created successfully, the client doesn't support XMLHttpRequest)
var myObj = new xhr();

//POST or GET or HEAD
//async or sync

//NB. only need to pass fnWhenDone for async mode


//post to mypage.php with args foo and bar
myObj.connect('mypage.php','POST','async','foo=bar&baz=qux',fnWhenDone);

or

//arr is an array e.g.
var arr = new Array(Array('usr_username',un)
                   ,Array('usr_password',pw)
                   ,Array('usertype',ut=='enter'?'par':ut));

myObj.connectarray('logon_process.php','POST','sync',arr,fnWhenDone);

or

//frm is an html form object
myObj.connectform(frm,'sync',fnWhenDone);


//if mode is sync when the server responds, the event will trigger the specified function
//if the mode is sync the response will be returned in the objects response.value property

// if sync: alert(myObj.response.value)

function fnWhenDone(res)
{
  alert(res);

//if XML is returned - header is text/xml
//	alert(res.getElementsByTagName('method')[0].firstChild.data+'\n'+res.getElementsByTagName('result')[0].firstChild.data);

//	method    = response.getElementsByTagName('method')[0].firstChild.data;
//	result    = response.getElementsByTagName('result')[0].firstChild.data;
//	eval(method + '(\'\', result)');

//if JSON is returned - header is text/html or text/plain
//convert text to object
//	var myObject = eval('(' + res + ')');

//or use a JSON parser - safer
//	var myObject = JSON.parse(aJSONtext);

//	alert(myObject.method+'\n'+myObject.result);
}


in the php program:
-------------------

set headers - good practice
//header('Content-Type: text/xml');
//header('Content-Type: text/html'); //default
//header('Content-Type: text/plain');

if return xml
//echo '
//<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
//<response>
//  <method>checkName</method>
//  <result>1</result>
//</response>';

if return JSON
//echo '{"method":"checkName","result":"1"}';


//===== END OF NEW XMLHTTPREQUEST FUNCTION USE =====
*/

