docs: function UFDS(opts) {
      assert.object(opts, 'options');
      assert.string(opts.bindDN, 'options.bindDN');
      assert.string(opts.bindPassword, 'options.bindPassword');
      assert.ok(!opts.bindCredentials, 'options.bindCredentials not supported');
      assert.optionalObject(opts.log, 'options.log');
      assert.string(opts.url, 'options.url');
  
      var self = this;
      EventEmitter.call(this);
  
      this.cacheOptions = clone(opts.cache || false);
      this.cache =
          this.cacheOptions ? cache.createCache(this.cacheOptions) : null;
      this.log = (opts.log || DEF_LOG).child({component: 'ufds'}, true);
  
      this.ldapOpts = {
          connectTimeout: opts.connectTimeout,
          credentials: {
              dn: opts.bindDN,
              passwd: opts.bindPassword
          },
          log: self.log,
          reconnect: {
              maxDelay: 30000,
              failAfter: Infinity
          },
          tlsOptions: {
              rejectUnauthorized: false
          },
          timeout: opts.clientTimeout || opts.timeout,
          url: opts.url,
          idleTimeout: opts.idleTimeout || 90000,
          queueSize: 10,
          queueTimeout: 200
      };
      if (opts.retry) {
          if (opts.retry.maxTimeout) {
              this.ldapOpts.reconnect.maxDelay = opts.retry.maxTimeout;
          }
          if (opts.retry.maxDelay) {
              this.ldapOpts.reconnect.maxDelay = opts.retry.maxDelay;
          }
          if (opts.retry.retries) {
              this.ldapOpts.reconnect.failAfter = opts.retry.retries;
          }
      }
  
      this.failFast = opts.failFast;
      this.hidden = opts.hidden;
  
      this.__defineGetter__('connected', function () {
          return self.client.connected;
      });
  
      this.connect();
  }