text: // Copyright 2004 Google Inc.
  // All Rights Reserved.
  //
  // A bunch of XML HTTP recipes used to do RPC from within javascript from
  // Gagan Saksena's wiki page
  // http://wiki.corp.google.com/twiki/bin/view/Main/JavaScriptRecipes
  
  /** Candidate Active X types.
    * @private
    */
  var _XH_ACTIVE_X_IDENTS = [
    "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0",
    "MSXML2.XMLHTTP", "MICROSOFT.XMLHTTP.1.0", "MICROSOFT.XMLHTTP.1",
    "MICROSOFT.XMLHTTP" ];
  /** The active x identifier used for ie.
   * @private
   */
  var _xh_ieProgId = undefined;
  
  // Domain for XmlHTTPRequest.readyState
  var XML_READY_STATE_UNINITIALIZED  = 0;
  var XML_READY_STATE_LOADING        = 1;
  var XML_READY_STATE_LOADED         = 2;
  var XML_READY_STATE_INTERACTIVE    = 3;
  var XML_READY_STATE_COMPLETED      = 4;
  
  /** initialize the private state used by other functions.
    * @private
    */
  function _XH_XmlHttpInit() {
    // Nobody (on the web) is really sure which of the progid's listed is totally
    // necessary. It is known, for instance, that certain installations of IE will
    // not work with only Microsoft.XMLHTTP, as well as with MSXML2.XMLHTTP.
    // Safest course seems to be to do this -- include all known progids for
    // XmlHttp.
    if (typeof XMLHttpRequest == 'undefined' &&
        typeof ActiveXObject != 'undefined') {
      for (var i = 0; i < _XH_ACTIVE_X_IDENTS.length; i++) {
        var candidate = _XH_ACTIVE_X_IDENTS[i];
  
        try {
          new ActiveXObject(candidate);
          _xh_ieProgId = candidate;
          break;
        } catch (e) {
          // do nothing; try next choice
        }
      }
  
      // couldn't find any matches
      if (undefined === _xh_ieProgId) {
        throw ("Could not create ActiveXObject. ActiveX might be disabled, or " +
               "msxml might not be installed");
      }
    }
  }
  
  _XH_XmlHttpInit();
  
  /** create and return an xml http request object that can be passed to
    * {@link #XH_XmlHttpGET} or {@link #XH_XmlHttpPOST}.
    */
  function XH_XmlHttpCreate() {
    if (_xh_ieProgId !== undefined) {
      return new ActiveXObject(_xh_ieProgId);
    } else {
      return new XMLHttpRequest();
    }
  }
  
  /** send a get request.
    * @param xmlhttp as from {@link XH_XmlHttpCreate}.
    * @param url the service to contact
    * @param handler function called when the response is received.
    */
  function XH_XmlHttpGET(xmlhttp, url, handler) {
    xmlhttp.onreadystatechange = handler;
    xmlhttp.open("GET", url, true);
    XH_XmlHttpSend(xmlhttp, null);
  }
  
  /** send a post request.
    * @param xmlhttp as from {@link XH_XmlHttpCreate}.
    * @param url the service to contact
    * @param data the request content.
    * @param handler function called when the response is received.
    */
  function XH_XmlHttpPOST(xmlhttp, url, data, handler) {
    xmlhttp.onreadystatechange = handler;
    xmlhttp.open("POST", url, true);
    xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xmlhttp.setRequestHeader("Content-Length", data.length);
    XH_XmlHttpSend(xmlhttp, data);
  }
  
  function XH_XmlHttpOpen(xmlhttp, verb, url, handler) {
    xmlhttp.onreadystatechange = handler;
    xmlhttp.open(verb, url, true);
  }
  
  function XH_XmlHttpSetRequestHeader(xmlhttp, name, value) {
    xmlhttp.setRequestHeader(name, value);
  }
  
  function XH_XmlHttpSend(xmlhttp, data) {
    try {
      xmlhttp.send(data);
    } catch (e) {
      // you may want to log/debug this error
      // one that you should be aware of is e.number == -2146697208,
      // which occurs when the 'Languages...' setting in IE is empty.
      log('XMLHttpSend failed ' + e.toString() + '<br>' + e.stack);
      throw e;
    }
  }
  
  function XH_XmlHttpAbort(xmlhttp) {
    // IE crashes if you NULL out the onreadystatechange synchronously
    SafeTimeout(window, function() {
      xmlhttp.onreadystatechange = function() {};
    }, 0);
    if (xmlhttp.readyState < XML_READY_STATE_COMPLETED) {
      xmlhttp.abort();
    }
  }
  