text: var request = Npm.require('request');
  var url_util = Npm.require('url');
  
  // _call always runs asynchronously; HTTP.call, defined below,
  // wraps _call and runs synchronously when no callback is provided.
  var _call = function(method, url, options, callback) {
  
    ////////// Process arguments //////////
  
    if (! callback && typeof options === "function") {
      // support (method, url, callback) argument list
      callback = options;
      options = null;
    }
  
    options = options || {};
  
    method = (method || "").toUpperCase();
  
    if (! /^https?:\/\//.test(url))
      throw new Error("url must be absolute and start with http:// or https://");
  
    var url_parts = url_util.parse(url);
  
    var headers = {};
  
    var content = options.content;
    if (options.data) {
      content = JSON.stringify(options.data);
      headers['Content-Type'] = 'application/json';
    }
  
    var responseType = options.responseType || "string";
    var encoding = _.isUndefined(options._encoding) ? "utf8" : options._encoding;
  
    // If responseType requires getting a Buffer back, override encoding
    // to null, which tells request to return a Buffer
    if (_.contains(["arraybuffer", "buffer", "ejson-binary"], responseType)) {
      encoding = null;
    }
  
    var params_for_url, params_for_body;
    if (content || method === "GET" || method === "HEAD")
      params_for_url = options.params;
    else
      params_for_body = options.params;
  
    var new_url = buildUrl(
      url_parts.protocol + "//" + url_parts.host + url_parts.pathname,
      url_parts.search, options.query, params_for_url);
  
    if (options.auth) {
      if (options.auth.indexOf(':') < 0)
        throw new Error('auth option should be of the form "username:password"');
      headers['Authorization'] = "Basic "+
        (new Buffer(options.auth, "ascii")).toString("base64");
    }
  
    if (params_for_body) {
      content = encodeParams(params_for_body);
      headers['Content-Type'] = "application/x-www-form-urlencoded";
    }
  
    _.extend(headers, options.headers || {});
  
    // wrap callback to add a 'response' property on an error, in case
    // we have both (http 4xx/5xx error, which has a response payload)
    callback = (function(callback) {
      return function(error, response) {
        if (error && response)
          error.response = response;
        callback(error, response);
      };
    })(callback);
  
    // safety belt: only call the callback once.
    callback = _.once(callback);
  
  
    ////////// Kickoff! //////////
  
    var req_options = {
      url: new_url,
      method: method,
      encoding: encoding,
      jar: false,
      timeout: options.timeout,
      body: content,
      followRedirect: options.followRedirects,
      headers: headers
    };
  
    request(req_options, function(error, res, body) {
      var response = null;
  
      if (! error) {
  
        response = {};
        response.statusCode = res.statusCode;
  
        // Convert body into requested type
        switch (responseType) {
          case "arraybuffer":
            var len = body.length;
            var ab = new ArrayBuffer(len);
            var view = new Uint8Array(ab);
            for (var i = 0; i < len; i++) {
              view[i] = body[i];
            }
            body = ab;
            break;
          case "ejson-binary":
            var len = body.length;
            var binary = EJSON.newBinary(len);
            for (var i = 0; i < len; i++) {
              binary[i] = body[i];
            }
            body = binary;
            break;
          case "json":
            if (typeof body === "string") {
              try {
                body = JSON.parse(body);
              } catch (err) {
                // leave it as a string
              }
            }
            break;
        }
  
  
        response.content = body;
        response.headers = res.headers;
  
        populateData(response);
  
        if (response.statusCode >= 400)
          error = makeErrorByStatus(response.statusCode, response.content);
      }
  
      callback(error, response);
  
    });
  };
  
  HTTP.call = Meteor.wrapAsync(_call);
  
  