text: /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for 
   * full list of contributors). Published under the 2-clause BSD license.
   * See license.txt in the OpenLayers distribution or repository for the
   * full text of the license. */
  
  /**
   * @requires OpenLayers/Events.js
   * @requires OpenLayers/Request/XMLHttpRequest.js
   */
  
  /**
   * TODO: deprecate me
   * Use OpenLayers.Request.proxy instead.
   */
  OpenLayers.ProxyHost = "";
  
  /**
   * Namespace: OpenLayers.Request
   * The OpenLayers.Request namespace contains convenience methods for working
   *     with XMLHttpRequests.  These methods work with a cross-browser
   *     W3C compliant <OpenLayers.Request.XMLHttpRequest> class.
   */
  if (!OpenLayers.Request) {
      /**
       * This allows for OpenLayers/Request/XMLHttpRequest.js to be included
       * before or after this script.
       */
      OpenLayers.Request = {};
  }
  OpenLayers.Util.extend(OpenLayers.Request, {
      
      /**
       * Constant: DEFAULT_CONFIG
       * {Object} Default configuration for all requests.
       */
      DEFAULT_CONFIG: {
          method: "GET",
          url: window.location.href,
          async: true,
          user: undefined,
          password: undefined,
          params: null,
          proxy: OpenLayers.ProxyHost,
          headers: {},
          data: null,
          callback: function() {},
          success: null,
          failure: null,
          scope: null
      },
      
      /**
       * Constant: URL_SPLIT_REGEX
       */
      URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,
      
      /**
       * APIProperty: events
       * {<OpenLayers.Events>} An events object that handles all 
       *     events on the {<OpenLayers.Request>} object.
       *
       * All event listeners will receive an event object with three properties:
       * request - {<OpenLayers.Request.XMLHttpRequest>} The request object.
       * config - {Object} The config object sent to the specific request method.
       * requestUrl - {String} The request url.
       * 
       * Supported event types:
       * complete - Triggered when we have a response from the request, if a
       *     listener returns false, no further response processing will take
       *     place.
       * success - Triggered when the HTTP response has a success code (200-299).
       * failure - Triggered when the HTTP response does not have a success code.
       */
      events: new OpenLayers.Events(this),
      
      /**
       * Method: makeSameOrigin
       * Using the specified proxy, returns a same origin url of the provided url.
       *
       * Parameters:
       * url - {String} An arbitrary url
       * proxy {String|Function} The proxy to use to make the provided url a
       *     same origin url.
       *
       * Returns
       * {String} the same origin url. If no proxy is provided, the returned url
       *     will be the same as the provided url.
       */
      makeSameOrigin: function(url, proxy) {
          var sameOrigin = url.indexOf("http") !== 0;
          var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX);
          if (urlParts) {
              var location = window.location;
              sameOrigin =
                  urlParts[1] == location.protocol &&
                  urlParts[3] == location.hostname;
              var uPort = urlParts[4], lPort = location.port;
              if (uPort != 80 && uPort != "" || lPort != "80" && lPort != "") {
                  sameOrigin = sameOrigin && uPort == lPort;
              }
          }
          if (!sameOrigin) {
              if (proxy) {
                  if (typeof proxy == "function") {
                      url = proxy(url);
                  } else {
                      url = proxy + encodeURIComponent(url);
                  }
              }
          }
          return url;
      },
  
      /**
       * APIMethod: issue
       * Create a new XMLHttpRequest object, open it, set any headers, bind
       *     a callback to done state, and send any data.  It is recommended that
       *     you use one <GET>, <POST>, <PUT>, <DELETE>, <OPTIONS>, or <HEAD>.
       *     This method is only documented to provide detail on the configuration
       *     options available to all request methods.
       *
       * Parameters:
       * config - {Object} Object containing properties for configuring the
       *     request.  Allowed configuration properties are described below.
       *     This object is modified and should not be reused.
       *
       * Allowed config properties:
       * method - {String} One of GET, POST, PUT, DELETE, HEAD, or
       *     OPTIONS.  Default is GET.
       * url - {String} URL for the request.
       * async - {Boolean} Open an asynchronous request.  Default is true.
       * user - {String} User for relevant authentication scheme.  Set
       *     to null to clear current user.
       * password - {String} Password for relevant authentication scheme.
       *     Set to null to clear current password.
       * proxy - {String} Optional proxy.  Defaults to
       *     <OpenLayers.ProxyHost>.
       * params - {Object} Any key:value pairs to be appended to the
       *     url as a query string.  Assumes url doesn't already include a query
       *     string or hash.  Typically, this is only appropriate for <GET>
       *     requests where the query string will be appended to the url.
       *     Parameter values that are arrays will be
       *     concatenated with a comma (note that this goes against form-encoding)
       *     as is done with <OpenLayers.Util.getParameterString>.
       * headers - {Object} Object with header:value pairs to be set on
       *     the request.
       * overrideMimeType - (String) Optional MIME type to override for the response.
       * data - {String | Document} Optional data to send with the request.
       *     Typically, this is only used with <POST> and <PUT> requests.
       *     Make sure to provide the appropriate "Content-Type" header for your
       *     data.  For <POST> and <PUT> requests, the content type defaults to
       *     "application-xml".  If your data is a different content type, or
       *     if you are using a different HTTP method, set the "Content-Type"
       *     header to match your data type.
       * callback - {Function} Function to call when request is done.
       *     To determine if the request failed, check request.status (200
       *     indicates success).
       * success - {Function} Optional function to call if request status is in
       *     the 200s.  This will be called in addition to callback above and
       *     would typically only be used as an alternative.
       * failure - {Function} Optional function to call if request status is not
       *     in the 200s.  This will be called in addition to callback above and
       *     would typically only be used as an alternative.
       * scope - {Object} If callback is a public method on some object,
       *     set the scope to that object.
       *
       * Returns:
       * {XMLHttpRequest} Request object.  To abort the request before a response
       *     is received, call abort() on the request object.
       */
      issue: function(config) {        
          // apply default config - proxy host may have changed
          var defaultConfig = OpenLayers.Util.extend(
              this.DEFAULT_CONFIG,
              {proxy: OpenLayers.ProxyHost}
          );
          config = config || {};
          config.headers = config.headers || {};
          config = OpenLayers.Util.applyDefaults(config, defaultConfig);
          config.headers = OpenLayers.Util.applyDefaults(config.headers, defaultConfig.headers);
          // Always set the "X-Requested-With" header to signal that this request
          // was issued through the XHR-object. Since header keys are case 
          // insensitive and we want to allow overriding of the "X-Requested-With"
          // header through the user we cannot use applyDefaults, but have to 
          // check manually whether we were called with a "X-Requested-With"
          // header.
          var customRequestedWithHeader = false,
              headerKey;
          for(headerKey in config.headers) {
              if (config.headers.hasOwnProperty( headerKey )) {
                  if (headerKey.toLowerCase() === 'x-requested-with') {
                      customRequestedWithHeader = true;
                  }
              }
          }
          if (customRequestedWithHeader === false) {
              // we did not have a custom "X-Requested-With" header
              config.headers['X-Requested-With'] = 'XMLHttpRequest';
          }
  
          // create request, open, and set headers
          var request = new OpenLayers.Request.XMLHttpRequest();
          var url = OpenLayers.Util.urlAppend(config.url, 
              OpenLayers.Util.getParameterString(config.params || {}));
          url = OpenLayers.Request.makeSameOrigin(url, config.proxy);
          request.open(
              config.method, url, config.async, config.user, config.password
          );
          for(var header in config.headers) {
              request.setRequestHeader(header, config.headers[header]);
          }
          
          if (config.overrideMimeType) {
              request.overrideMimeType(config.overrideMimeType);
          }
  
          var events = this.events;
  
          // we want to execute runCallbacks with "this" as the
          // execution scope
          var self = this;
          
          request.onreadystatechange = function() {
              if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
                  var proceed = events.triggerEvent(
                      "complete",
                      {request: request, config: config, requestUrl: url}
                  );
                  if(proceed !== false) {
                      self.runCallbacks(
                          {request: request, config: config, requestUrl: url}
                      );
                  }
              }
          };
          
          // send request (optionally with data) and return
          // call in a timeout for asynchronous requests so the return is
          // available before readyState == 4 for cached docs
          if(config.async === false) {
              request.send(config.data);
          } else {
              window.setTimeout(function(){
                  if (request.readyState !== 0) { // W3C: 0-UNSENT
                      request.send(config.data);
                  }
              }, 0);
          }
          return request;
      },
      
      /**
       * Method: runCallbacks
       * Calls the complete, success and failure callbacks. Application
       *    can listen to the "complete" event, have the listener 
       *    display a confirm window and always return false, and
       *    execute OpenLayers.Request.runCallbacks if the user
       *    hits "yes" in the confirm window.
       *
       * Parameters:
       * options - {Object} Hash containing request, config and requestUrl keys
       */
      runCallbacks: function(options) {
          var request = options.request;
          var config = options.config;
          
          // bind callbacks to readyState 4 (done)
          var complete = (config.scope) ?
              OpenLayers.Function.bind(config.callback, config.scope) :
              config.callback;
          
          // optional success callback
          var success;
          if(config.success) {
              success = (config.scope) ?
                  OpenLayers.Function.bind(config.success, config.scope) :
                  config.success;
          }
  
          // optional failure callback
          var failure;
          if(config.failure) {
              failure = (config.scope) ?
                  OpenLayers.Function.bind(config.failure, config.scope) :
                  config.failure;
          }
  
          if (OpenLayers.Util.createUrlObject(config.url).protocol == "file:" &&
                                                          request.responseText) {
              request.status = 200;
          }
          complete(request);
  
          if (!request.status || (request.status >= 200 && request.status < 300)) {
              this.events.triggerEvent("success", options);
              if(success) {
                  success(request);
              }
          }
          if(request.status && (request.status < 200 || request.status >= 300)) {                    
              this.events.triggerEvent("failure", options);
              if(failure) {
                  failure(request);
              }
          }
      },
      
      /**
       * APIMethod: GET
       * Send an HTTP GET request.  Additional configuration properties are
       *     documented in the <issue> method, with the method property set
       *     to GET.
       *
       * Parameters:
       * config - {Object} Object with properties for configuring the request.
       *     See the <issue> method for documentation of allowed properties.
       *     This object is modified and should not be reused.
       * 
       * Returns:
       * {XMLHttpRequest} Request object.
       */
      GET: function(config) {
          config = OpenLayers.Util.extend(config, {method: "GET"});
          return OpenLayers.Request.issue(config);
      },
      
      /**
       * APIMethod: POST
       * Send a POST request.  Additional configuration properties are
       *     documented in the <issue> method, with the method property set
       *     to POST and "Content-Type" header set to "application/xml".
       *
       * Parameters:
       * config - {Object} Object with properties for configuring the request.
       *     See the <issue> method for documentation of allowed properties.  The
       *     default "Content-Type" header will be set to "application-xml" if
       *     none is provided.  This object is modified and should not be reused.
       * 
       * Returns:
       * {XMLHttpRequest} Request object.
       */
      POST: function(config) {
          config = OpenLayers.Util.extend(config, {method: "POST"});
          // set content type to application/xml if it isn't already set
          config.headers = config.headers ? config.headers : {};
          if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
              config.headers["Content-Type"] = "application/xml";
          }
          return OpenLayers.Request.issue(config);
      },
      
      /**
       * APIMethod: PUT
       * Send an HTTP PUT request.  Additional configuration properties are
       *     documented in the <issue> method, with the method property set
       *     to PUT and "Content-Type" header set to "application/xml".
       *
       * Parameters:
       * config - {Object} Object with properties for configuring the request.
       *     See the <issue> method for documentation of allowed properties.  The
       *     default "Content-Type" header will be set to "application-xml" if
       *     none is provided.  This object is modified and should not be reused.
       * 
       * Returns:
       * {XMLHttpRequest} Request object.
       */
      PUT: function(config) {
          config = OpenLayers.Util.extend(config, {method: "PUT"});
          // set content type to application/xml if it isn't already set
          config.headers = config.headers ? config.headers : {};
          if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
              config.headers["Content-Type"] = "application/xml";
          }
          return OpenLayers.Request.issue(config);
      },
      
      /**
       * APIMethod: DELETE
       * Send an HTTP DELETE request.  Additional configuration properties are
       *     documented in the <issue> method, with the method property set
       *     to DELETE.
       *
       * Parameters:
       * config - {Object} Object with properties for configuring the request.
       *     See the <issue> method for documentation of allowed properties.
       *     This object is modified and should not be reused.
       * 
       * Returns:
       * {XMLHttpRequest} Request object.
       */
      DELETE: function(config) {
          config = OpenLayers.Util.extend(config, {method: "DELETE"});
          return OpenLayers.Request.issue(config);
      },
    
      /**
       * APIMethod: HEAD
       * Send an HTTP HEAD request.  Additional configuration properties are
       *     documented in the <issue> method, with the method property set
       *     to HEAD.
       *
       * Parameters:
       * config - {Object} Object with properties for configuring the request.
       *     See the <issue> method for documentation of allowed properties.
       *     This object is modified and should not be reused.
       * 
       * Returns:
       * {XMLHttpRequest} Request object.
       */
      HEAD: function(config) {
          config = OpenLayers.Util.extend(config, {method: "HEAD"});
          return OpenLayers.Request.issue(config);
      },
      
      /**
       * APIMethod: OPTIONS
       * Send an HTTP OPTIONS request.  Additional configuration properties are
       *     documented in the <issue> method, with the method property set
       *     to OPTIONS.
       *
       * Parameters:
       * config - {Object} Object with properties for configuring the request.
       *     See the <issue> method for documentation of allowed properties.
       *     This object is modified and should not be reused.
       * 
       * Returns:
       * {XMLHttpRequest} Request object.
       */
      OPTIONS: function(config) {
          config = OpenLayers.Util.extend(config, {method: "OPTIONS"});
          return OpenLayers.Request.issue(config);
      }
  
  });
  