anchor.diff:    ///      // Authenticated bind
     ///      LDAPConfiguration.settings("ldap.example.com", ssl: true, bindDN: "cn=admin,dc=example,dc=com", password: "p@ssw0rd");
   
  -  LDAPConfiguration(String hostname, { bool ssl: false, int port: null, String bindDN: "", String password: "" }) {
  -
  -     if (hostname == null) {
  -       hostname = "localhost";
  -     }
  -
  -     if (port == null) {
  -       port = (ssl) ? 636 : 389; // standard LDAPS and LDAP ports
  -     }
  -
  -     configMap = new Map<String,Map>();
  -     var m = new Map();
  -     configMap[_configName] = m;
  -
  -     m["ssl"] = ssl;
  -     m["host"] = hostname;
  -     m["port"] = port;
  -     m["bindDN"] = bindDN;
  -     m["password"] = password;
  -   }
  -
  -  /// Creates a new LDAP configuration from a configuration Map in a YAML file.
  -  ///
  -  /// If [_fileName] is provided it is used as the filename of a YAML file
  -  /// containing the LDAP connection parameters. It defaults to `ldap.yaml` in
  -  /// the current directory if not provided.
  -  ///
  -  /// The optional parameter [_configName] is the name of a config in the YAML
  +  LDAPConfiguration(String hostname, {bool ssl: false, int port: null,
  +      String bindDN: null, String password: null}) {
  +    _setAll(hostname, port, ssl, bindDN, password);
  +  }
  +
  +  /// Constructor for a new LDAP configuration from a YAML file.
  +  ///
  +  /// The [fileName] is the name of a YAML file
  +  /// containing the LDAP connection settings.
  +  ///
  +  /// The optional parameter [configName] is the name of a Map in the YAML
     /// file. It defaults to "default".
     ///
     /// # Example
  
positive.code: 
  Logger logger = new Logger("ldap_configuration");
  
  /// A LDAP configuration settings and the underlying LDAP connection.
  ///
  /// Use an instance of this class to represent the LDAP configuration
  /// settings (host, port, bind distinguished name, password, and
  /// whether the connection uses TLS/SSL).
  ///
  /// It is also used to obtain an [LDAPConnection] using those settings.
  ///
  /// There are three ways to create an LDAP configuration:
  ///
  /// * Providing the settings as parameters using the [settings] constructor.
  /// * Providing the settings in a Map using the [fromMap] constructor.
  /// * Loading the settings from a YAML file using the default constructor.
  
  class LDAPConfiguration {
  
    LDAPConnection _connection;
  
    String _fileName;
    Map configMap;
  
    String  _configName = "default";
  
    Map get config => configMap[_configName];
  
    /// Returns the bind distinguished name.
    String get bindDN   => config['bindDN'];
    /// Returns the password.
    String get password => config['password'];
    /// Returns the LDAP server host.
    String get host     => config['host'];
    /// Returns the LDAP server port number.
    int    get port     => config['port'];
  
    /// Returns true if the connection is TLS/SSL, false otherwise.
    bool get ssl {
      var x = config['ssl'];
      if( x == null || x != true)
        return false;
      return true;
    }
  
    /// Creates a new LDAP configuration.
    ///
    /// The [hostname] is the hostname of the LDAP server.
    ///
    /// Set [ssl] to true to connect over TLS, otherwise TLS is not used. It
    /// defaults to false.
    ///
    /// The [port] is the port number of the LDAP server. It defaults to the
    /// standard LDAP port numbers: 389 when TLS is not used or 636 when TLS is
    /// used.
    ///
    /// Set [bindDN] to the distinguish name for the bind. An empty string
    /// means to perform an anonymous bind.  It defaults to an empty string.
    ///
  
negative.code:   ///     default:
    ///       host: "ldap.example.com"
    ///       port: 389
    ///       ssl: false
    ///       bindDN: "cn=admin,dc=example,dc=com"
    ///       password: "p@ssw0rd"
    ///
    ///  The only mandatory attribute is "host". See the default constructor
    ///  for a description of the other attributes, and their values if they are not specified.
  
    LDAPConfiguration.fromFile(String fileName, [String configName]) {
      assert(fileName != null && fileName.isNotEmpty);
      assert(configName == null || configName.isNotEmpty);
  
      this._fileName = fileName;
      this._configName = (configName != null) ? configName : _DEFAULT_CONFIG_NAME;
    }
  
    /// Loads the settings from the YAML file, if needed.
    ///
    /// If the LDAPConfiguration was not created using the fromFile constructor, this method
    /// does nothign and returns immediately.
  
    Future _load_values() async {
      if (_fileName == null) {
        // No file to load: settings are already set
        return;
      } else {
        // Load settings from file
  
        var configMap = await server_config.loadConfig(_fileName);
  
        var m = configMap[_configName];
  
        if (m == null) {
          throw new LDAPException("${_fileName}: missing \"${_configName}\"");
        }
        if (!(m is Map)) {
          throw new LDAPException(
              "${_fileName}: \"${_configName}\" is not a map");
        }
  
        // Get and check the host
  
        var host_value = m["host"];
        if (host_value == null) {
          throw new LDAPException(
              "${_fileName}: \"${_configName}\" missing \"host\"");
        }
        if (!(host_value is String)) {
          throw new LDAPException(
              "${_fileName}: host in \"${_configName}\" is not a string");
        }
  
        // Get and check the port
  
        var port_value = m["port"];
        if (port_value != null && !(port_value is int)) {
          throw new LDAPException(
              "${_fileName}: port in \"${_configName}\" is not an int");
        }
  
        // Get and check the ssl
  
        var ssl_value = m["ssl"];
        if (ssl_value != null && !(ssl_value is bool)) {
          throw new LDAPException(
              "${_fileName}: ssl in \"${_configName}\" is not true/false");
        }
  
        // Get and check bindDN
  
        var bindDN_value = m["bindDN"];
        if (bindDN_value != null && !(bindDN_value is String)) {
          throw new LDAPException(
              "${_fileName}: bindDN in \"${_configName}\" is not a string");
        }
  
        // Get and check password
  
        var password_value = m["password"];
        if (password_value != null && !(password_value is String)) {
          throw new LDAPException(
              "${_fileName}: password in \"${_configName}\" is not a string");
        }
  
        this._setAll(
            host_value, port_value, ssl_value, bindDN_value, password_value);
  
        _fileName = null; // prevent future invocations from reloading it
        return;
      }
    }
  
    /// Return a Future<[LDAPConnection]> using this configuration.
    ///
    /// The connection is cached so that subsequent calls will return
    /// the same connection (unless it has been closed, in which case
    /// a new one will be created).
    ///
    /// If the optional parameter [doBind] is true (the default),
    /// the returned connection will also be bound using the configured DN and password.
    ///
    /// The LDAP connection can be closed by invoking the `close` method on the
    /// [LDAPConfiguration] or by invoking the [LDAPConnection.close] method on the
    /// connection object.  Either approach will cause subsequent calls to
    /// this [getConnection] method to open a new LDAP connection.
  
    Future<LDAPConnection> getConnection([bool doBind = true]) async {
      if (_connection != null && !_connection.isClosed()) {
        // Use cached connection
        return _connection;
      }
  
      // Get settings (loading them from the YAML file if necessary)
  
      await _load_values();
  
      // Connect
  
      logger.info(
          "LDAP connection: ${ssl ? "ldaps://" : "ldap://"}${host}:${port}");
  
      _connection = new LDAPConnection(host, port, ssl, bindDN, password);
      await _connection.connect();
  
      // Bind
  
      if (doBind) {
        var r = await _connection.bind();
        if (r.resultCode != 0) throw new LDAPException("BIND Failed", r);
      }
  
      return _connection;
    }
  
    /// Closes the [LDAPconnection] that was opened with [getConnection].
  
    Future close([bool immediate = false]) {
      if (_connection != null) {
        var f = _connection.close(immediate);
        _connection = null;
        return f;
      } else {
        assert(_connection != null);
        return null;
      }
    }
  }
  