var getXHR = function() {
  var http = null;
  try {
    http = new XMLHttpRequest();
    getXHR = function() { return new XMLHttpRequest(); };
  } catch(e) {
    var MS_XML_HTTP = ['MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'];
    for (var i = 0; i < MS_XML_HTTP.length; ++i) {
      try {
        http = new ActiveXObject(MS_XML_HTTP[i]);
        getXHR = function() { return new ActiveXObject(MS_XML_HTTP[i]); };
        break;
      } catch(e) {}
    }
  }
  return http;
}
function request(url, properties) {
  var req = getXHR();
  req.open(properties.method ? properties.method : 'GET', url, !properties.sync, properties.username, properties.password);
  if (properties.method && (properties.method == 'POST' || properties.method == 'PUT')) req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
  if (properties.headers) {
    for (header in properties.headers) {
      req.setRequestHeader(header, properties.headers[header]);
    }
  }
  req.onreadystatechange = function() {
    if (properties.onreadystate && properties.onreadystate[req.readyState]) properties.onreadystate[req.readyState](req);
    if (req.readyState == 4) {
      if (properties.callback) {
        properties.callback(req);
      }
    }
  }
  if (properties.onreadystate && properties.onreadystate['beforeSend']) properties.onreadystate['beforeSend'](req);
  req.send(properties.method && (properties.method == 'POST' || properties.method == 'PUT') && properties.body ? properties.body: null);
  if (properties.onreadystate && properties.onreadystate['afterSend']) properties.onreadystate['afterSend'](req);
  return req;
}
function debug_req(req) {
  return req.status + ' ' + req.statusText + '<br>\n' + req.getAllResponseHeaders() + (req.responseText ? '<br>\n' + req.responseText : '') + (req.responseXML ? '<br>\n' + req.responseXML : '');
}
function sync_request_template(method, url, body, callback, onreadystate) {
  callback(request(url, {method: method, sync: true, body: body, onreadystate: onreadystate}));
}
function request_template(method, url, body, callback, onreadystate) {
  request(url, {method: method, body: body, callback: function(req) {
    callback(req);
  }, onreadystate: onreadystate});
}
/* Asynchronous request */
function HEAD(url, callback, onreadystate) { request_template('HEAD', url, null, callback, onreadystate); }
function GET(url, callback, onreadystate) { request_template('GET', url, null, callback, onreadystate); }
function POST(url, postData, callback, onreadystate) { request_template('POST', url, postData, callback, onreadystate); }
function PUT(url, putData, callback, onreadystate) { request_template('PUT', url, putData, callback, onreadystate); }
function DELETE(url, callback, onreadystate) { request_template('DELETE', url, null, callback, onreadystate); }
function OPTIONS(callback, onreadystate) { request_template('OPTIONS', null, null, callback, onreadystate); }
/* Synchronous request */
function sHEAD(url, callback, onreadystate) { sync_request_template('HEAD', url, null, callback, onreadystate); }
function sGET(url, callback, onreadystate) { sync_request_template('GET', url, null, callback, onreadystate); }
function sPOST(url, postData, callback, onreadystate) { sync_request_template('POST', url, postData, callback, onreadystate); }
function sPUT(url, putData, callback, onreadystate) { sync_request_template('PUT', url, putData, callback, onreadystate); }
function sDELETE(url, callback, onreadystate) { sync_request_template('DELETE', url, null, callback, onreadystate); }
function sOPTIONS(callback, onreadystate) { sync_request_template('OPTIONS', null, null, callback, onreadystate); }
