function Client (options) {
  assert.ok(options)

  EventEmitter.call(this, options)

  const self = this
  this.urls = options.url ? [].concat(options.url).map(url.parse) : []
  this._nextServer = 0
  // updated in connectSocket() after each connect
  this.host = undefined
  this.port = undefined
  this.secure = undefined
  this.url = undefined
  this.tlsOptions = options.tlsOptions
  this.socketPath = options.socketPath || false

  this.log = options.log.child({ clazz: 'Client' }, true)

  this.timeout = parseInt((options.timeout || 0), 10)
  this.connectTimeout = parseInt((options.connectTimeout || 0), 10)
  this.idleTimeout = parseInt((options.idleTimeout || 0), 10)
  if (options.reconnect) {
    // Fall back to defaults if options.reconnect === true
    const rOpts = (typeof (options.reconnect) === 'object')
      ? options.reconnect
      : {}
    this.reconnect = {
      initialDelay: parseInt(rOpts.initialDelay || 100, 10),
      maxDelay: parseInt(rOpts.maxDelay || 10000, 10),
      failAfter: parseInt(rOpts.failAfter, 10) || Infinity
    }
  }

  this.queue = requestQueueFactory({
    size: parseInt((options.queueSize || 0), 10),
    timeout: parseInt((options.queueTimeout || 0), 10)
  })
  if (options.queueDisable) {
    this.queue.freeze()
  }

  // Implicitly configure setup action to bind the client if bindDN and
  // bindCredentials are passed in.  This will more closely mimic PooledClient
  // auto-login behavior.
  if (options.bindDN !== undefined &&
      options.bindCredentials !== undefined) {
    this.on('setup', function (clt, cb) {
      clt.bind(options.bindDN, options.bindCredentials, function (err) {
        if (err) {
          if (self._socket) {
            self._socket.destroy()
          }
          self.emit('error', err)
        }
        cb(err)
      })
    })
  }

  this._socket = null
  this.connected = false
  this.connect()
}
Constructs a new client.

The options object is required, and must contain either a URL (string) or
a socketPath (string); the socketPath is only if you want to talk to an LDAP
server over a Unix Domain Socket.  Additionally, you can pass in a bunyan
option that is the result of `new Logger()`, presumably after you've
configured it.

@param {Object} options must have either url or socketPath.
@throws {TypeError} on bad input.