docs: function Pool(http, endpoints, options) {
      if (!http || !http.request || !http.Agent) {
          throw new Error("invalid http module");
      }
      if (! Array.isArray(endpoints)) {
          throw new Error("endpoints must be an array");
      }
      this.http = http;
  
      options = options || {};
      options.retry_filter = options.retry_filter || options.retryFilter;
      options.retry_delay = options.retry_delay || options.retryDelay;
      options.ping = options.ping || options.path;
      if (typeof options.max_retries === "number") {
          options.max_retries = options.max_retries;
      } else if (typeof options.maxRetries === "number") {
          options.max_retries = options.maxRetries;
      } else {
          options.max_retries = 5;
      }
  
      // retry_delay can be 0, which is useful but also falsy so we check for 0 explicitly
      if (!options.retry_delay && options.retry_delay !== 0) {
          options.retry_delay = 20;
      }
  
      this.name = options.name;
      this.options = options;
      this.max_pending = options.max_pending || options.maxPending || 1000;
      this.max_pool_size = options.max_pool_size || options.maxPoolSize;
      this.endpoints = [];
      this.endpoints_by_name = {};
  
      // clone
      this.all_hostports = endpoints.slice();
  
      if (this.max_pool_size !== undefined && this.max_pool_size !== null &&
          (typeof this.max_pool_size !== 'number' || this.max_pool_size < 1)) {
          throw new Error('max_pool_size invalid');
      }
  
      var selectedEndpoints = endpoints;
  
      if (this.max_pool_size < endpoints.length) {
          // simple resevoir sampling algorithm
          selectedEndpoints = new Array(this.max_pool_size);
          for (var j = 0; j < endpoints.length; j++) {
              if (j < this.max_pool_size) {
                  selectedEndpoints[j] = endpoints[j];
              } else {
                  // random replacement with decreasing probablity
                  var r = Math.floor(Math.random() * (j + 1));
                  if (r < this.max_pool_size) {
                      selectedEndpoints[r] = endpoints[j];
                  }
              }
          }
      }
  
      this.length = 0;
      for (var i = 0; i < selectedEndpoints.length; i++) {
          this.add_pool_endpoint(selectedEndpoints[i]);
      }
  
      if (this.endpoints.length === 0) {
          throw new Error("no valid endpoints");
      }
  
      // this special endpoint is returned when the pool is overloaded
      this.overloaded_endpoint = new GO.PoolEndpoint({Agent: Object}, null, null, {timeout: 0});
      this.overloaded_endpoint.special_endpoint = "overloaded";
      this.overloaded_endpoint.healthy = false;
      this.overloaded_endpoint.request = function (options, callback) {
          var err = new Error("too many pending requests");
          err.reason = "full";
          err.delay = true;
          err.attempt = { options: options };
          process.nextTick(function () {
              callback(err);
          });
      };
  
      // this special endpoint is returned when there are no healthy endpoints
      this.unhealthy_endpoint = new GO.PoolEndpoint({Agent: Object}, null, null, {timeout: 0});
      this.unhealthy_endpoint.special_endpoint = "unhealthy";
      this.unhealthy_endpoint.healthy = false;
      this.unhealthy_endpoint.request = function (options, callback) {
          var err = new Error("no healthy endpoints");
          err.reason = "unhealthy";
          err.delay = true;
          err.attempt = { options: options };
          process.nextTick(function () {
              callback(err);
          });
      };
  }