
  HTTPRequest = function() {};

  HTTPRequest.prototype.isSupported = function() {
    return !!this.getConnection();
  };

  HTTPRequest.prototype.events = ["start", "open", "send", "load", "end"];

//  HTTPRequest.prototype.filter = encodeURIComponent;

  HTTPRequest.prototype.getConnection = function() {
    var i;
    var o = [
      function(){return new ActiveXObject("Msxml2.XMLHTTP");},
      function(){return new ActiveXObject("Microsoft.XMLHTTP");},
      function(){return new XMLHttpRequest;}
    ];
    for (i = o.length; i--;) {
      try {
        return o[i]();
      }
      catch(e) {}
    }
    return null;
  };

  HTTPRequest.prototype.formatParams = function(params) {
    var i
    var r = [];

    for (i in params)
      r[r.length] = i + "=" + (this.filter ? this.filter(params[i]) : params[i]);
    return r.join("&");
  };

  HTTPRequest.prototype.setCallback = function(callback) {
    this.callback = callback; // {method: , params: {}}
  }

  HTTPRequest.prototype.get = function(url, params, handler, waitResponse) {
    return this.request("GET", url + (url.indexOf("?") + 1 ? "&" : "?") + this.formatParams(params), null, handler, null, waitResponse);
  };

  HTTPRequest.prototype.post = function(url, params, handler, waitResponse) {
    return this.request("POST", url, params = this.formatParams(params), handler, {
//      "Connection": "close",
      "Content-Length": params.length,
      "Method": "POST " + url + " HTTP/1.1",
      "Content-Type": "application/x-www-form-urlencoded; charset=utf-8"
    }, waitResponse);
  };

  HTTPRequest.prototype.request = function(method, url, params, handler, headers, waitResponse) {
    var i;
    var o = this.getConnection();
    var f = handler instanceof Function;
    var callback = this.callback;

    try {
      o.open(method, url, !waitResponse);
      waitResponse || (o.onreadystatechange = function() {
        var s = HTTPRequest.prototype.events[o.readyState];
        f ? handler(o) : s in handler && handler[s](o, callback);
      });
      if (headers) {
        for (i in {USER_AGENT: 0, XUSER_AGENT: 0})
            i in headers || (headers[i] = "XMLHttpRequest");
        for (i in headers)
            o.setRequestHeader(i, headers[i]);
      }
      o.send(params);
      waitResponse && (f ? handler(o) : handler["end"] && handler["end"](o, callback));
      return true;
    }
    catch (e) {
      alert('HTTPRequest error: ' + e);
      return false;
    }
  };

  function request(a_params, a_callback, a_wait_response, a_script) {
    var r = new HTTPRequest;
    r.setCallback(a_callback);
    var script = (a_script == undefined ? 'index.php' : a_script);
    return r.post(script, a_params, {end: requestCallback}, a_wait_response);
  }

  function submit(a_call, a_area, a_callback, a_script) {
    this.area = a_area ? document.getElementById(a_area) : document;
    this.fields = Array();
    this.fields['call'] = a_call;
    this.addFields = function(a_name) {
      var fields = this.area.getElementsByTagName(a_name);
      for (i = 0; i < fields.length; i++) {
        if (fields[i].id) {
          if (fields[i].type == 'checkbox')
            this.fields[fields[i].id] = fields[i].checked;
          else
            this.fields[fields[i].id] = fields[i].value;
        }
      }
    }
    addFields('input');
    addFields('textarea');
    addFields('select');
    return request(this.fields, a_callback, null, a_script);
  }

  function showResponse(o) {
//    document.body.innerHTML =
//      '<pre><b>Error</b>: Server response have not process callback on client side for message type ' +
//      o.getResponseHeader('content-type') + '<br />' + o.responseText + '</pre>';
    alert(
      'Error: Server response have not process callback on client side for message type ' +
      o.getResponseHeader('content-type') + '\n\n' + o.responseText);
  }

  function jsonEncode(a_json) {
    try {
      eval('var result = ' + a_json);
      return result;
    }
    catch (e) {
      alert('jsonEncode: ' + e + '\n' + a_json);
    }
  }

  function requestCallback(o, callback) {
    try {
      if (o.getResponseHeader('content-type').indexOf('application/x-json') != -1)
        callback ? callback.method(jsonEncode(o.responseText), callback.params) : showResponse(o);
      else if (o.getResponseHeader('content-type').indexOf('text/javascript') != -1)
        callback ? callback.method(o.responseText, callback.params) : eval(o.responseText);
      else
        document.body.innerHTML = o.responseText;
    }
    catch (e) {
//showResponse(o);
//      alert('requestCallback: ' + e + '\n\n' + o.responseText);
//showResponse(o);
//      document.body.innerHTML = 'requestCallback: ' + e;
    }
  }
