/// <summary>
        /// Perform a blacklist query.
        /// </summary>
        /// <param name="Lookup">Supplies the query input parameters.</param>
        /// <returns>True if the query matches a blacklist entry.</returns>
        public bool IsBlacklisted(BlacklistLookup Lookup)
        {
            //
            // Locally capture the current blacklist and sweep through the list
            // searching for a match.
            //

            var LocalBlacklist = Blacklist;

            foreach (BlacklistEntry Entry in LocalBlacklist)
            {
                if (Lookup.ServerAddress != null && Entry.IsBlacklistMatched(Lookup.ServerAddress.ToString(), BlacklistEntry.BlacklistType.BlacklistTypeServerAddress))
                {
                    return(true);
                }
                if (Lookup.ModuleName != null && Entry.IsBlacklistMatched(Lookup.ModuleName, BlacklistEntry.BlacklistType.BlacklistTypeModuleName))
                {
                    return(true);
                }
            }

            return(false);
        }
        /// <summary>
        /// Prepare the database, creating tables (if they did not already
        /// exist).
        /// </summary>
        private void InitializeDatabase()
        {
            uint ServersAdded;

            if (String.IsNullOrEmpty(MasterServer.ConnectionString))
            {
                return;
            }

            try
            {
                MasterServer.ExecuteQueryNoReader(
                    @"CREATE TABLE IF NOT EXISTS `game_servers` (
    `game_server_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `product_id` int(10) UNSIGNED NOT NULL,
    `expansions_mask` int(10) UNSIGNED NOT NULL,
    `build_number` int(10) UNSIGNED NOT NULL,
    `module_name` varchar(32) NOT NULL,
    `server_name` varchar(256) NOT NULL,
    `active_player_count` int(10) UNSIGNED NOT NULL,
    `maximum_player_count` int(10) UNSIGNED NOT NULL,
    `local_vault` bool NOT NULL,
    `last_heartbeat` datetime NOT NULL,
    `server_address` varchar(128) NOT NULL,
    `online` bool NOT NULL,
    `private_server` bool NOT NULL,
    `module_description` varchar(256) NOT NULL,
    `module_url` varchar(256) NOT NULL,
    `game_type` int(10) UNSIGNED NOT NULL,
    `minimum_level` int(10) UNSIGNED NOT NULL,
    `maximum_level` int(10) UNSIGNED NOT NULL,
    `pvp_level` int(10) UNSIGNED NOT NULL,
    `player_pause` bool NOT NULL,
    `one_party_only` bool NOT NULL,
    `elc_enforced` bool NOT NULL,
    `ilr_enforced` bool NOT NULL,
    `pwc_url` varchar(256) NOT NULL,
    `server_description` varchar(256) NOT NULL,
    `game_server_group_id` int(10) UNSIGNED,
    PRIMARY KEY (`game_server_id`),
    UNIQUE KEY (`product_id`, `server_address`),
    INDEX (`product_id`, `online`),
    INDEX (`product_id`, `online`, `server_name`),
    INDEX (`product_id`, `online`, `module_name`),
    INDEX (`product_id`, `online`, `game_type`),
    INDEX (`product_id`, `online`, `game_server_group_id`)
    )");

                MasterServer.ExecuteQueryNoReader(
                    @"CREATE TABLE IF NOT EXISTS `game_server_groups` (
    `game_server_group_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `product_id` int(10) UNSIGNED NOT NULL,
    `group_name` varchar(128) NOT NULL,
    `global_user_counts` bool NOT NULL,
    PRIMARY KEY (`game_server_group_id`),
    UNIQUE KEY (`product_id`, `group_name`)
    )");

                MasterServer.ExecuteQueryNoReader(
                    @"CREATE TABLE IF NOT EXISTS `pending_game_servers` (
    `pending_game_server_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `product_id` int(10) UNSIGNED NOT NULL,
    `server_address` varchar(128) NOT NULL,
    PRIMARY KEY (`pending_game_server_id`),
    UNIQUE KEY (`product_id`, `server_address`)
    )");

                MasterServer.ExecuteQueryNoReader(
                    @"CREATE TABLE IF NOT EXISTS `client_extension_update` (
    `update_id` int(10) UNSIGNED NOT NULL,
    `product_id` int(10) UNSIGNED NOT NULL,
    `update_message` varchar(4096) NOT NULL,
    `update_url` varchar(4096) NOT NULL,
    `update_info_url` varchar(4096) NOT NULL,
    `update_version` varchar(128) NOT NULL,
    `update_motd` varchar(4096) NOT NULL,
    PRIMARY KEY (`update_id`)
    )");

                MasterServer.ExecuteQueryNoReader(
                    @"CREATE TABLE IF NOT EXISTS `stat_counters` (
    `stat_counter_name` varchar(64) NOT NULL,
    `stat_counter_value` int(10) UNSIGNED NOT NULL,
    `stat_counter_last_update` datetime NOT NULL,
    PRIMARY KEY (`stat_counter_name`)
    )");

                MasterServer.ExecuteQueryNoReader(
                    @"CREATE TABLE IF NOT EXISTS `blacklist_entries` (
    `blacklist_entry_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `product_id` int(10) UNSIGNED NOT NULL,
    `blacklist_entry_type` int(10) UNSIGNED NOT NULL,
    `blacklist_entry_match` varchar(128) NOT NULL,
    PRIMARY KEY (`blacklist_entry_id`)
    )");

                string Query = String.Format(
                    @"SELECT `game_server_id`,
    `expansions_mask`,
    `build_number`,
    `module_name`,
    `server_name`,
    `active_player_count`,
    `maximum_player_count`,
    `local_vault`,
    `last_heartbeat`,
    `server_address`,
    `online`,
    `private_server`,
    `module_description`,
    `module_url`,
    `game_type`,
    `minimum_level`,
    `maximum_level`,
    `pvp_level`,
    `player_pause`,
    `one_party_only`,
    `elc_enforced`,
    `ilr_enforced`,
    `pwc_url`, 
    `server_description` 
FROM `game_servers`
WHERE `product_id` = {0}
AND `online` = true",
                    MasterServer.ProductID);

                RefreshBlacklist();

                ServersAdded = 0;
                using (MySqlDataReader Reader = MasterServer.ExecuteQuery(Query))
                {
                    while (Reader.Read())
                    {
                        uint       ServerId = Reader.GetUInt32(0);
                        string     Hostname = Reader.GetString(9);
                        int        i        = Hostname.IndexOf(':');
                        IPEndPoint ServerAddress;

                        if (i == -1)
                        {
                            Logger.Log(LogLevel.Error, "NWServerTracker.InitializeDatabase(): Server {0} has invalid hostname '{1}'.",
                                       ServerId,
                                       Hostname);
                            continue;
                        }

                        try
                        {
                            ServerAddress = new IPEndPoint(
                                IPAddress.Parse(Hostname.Substring(0, i)),
                                Convert.ToInt32(Hostname.Substring(i + 1)));
                        }
                        catch (Exception e)
                        {
                            Logger.Log(LogLevel.Error, "NWServerTracker.InitializeDatabase(): Error initializing hostname {0} for server {1}: Exception: {2}",
                                       Hostname,
                                       ServerId,
                                       e);
                            continue;
                        }

                        //
                        // Query for whether the server is blacklisted and do
                        // not re-list it if so.
                        //

                        BlacklistLookup Lookup = new BlacklistLookup();

                        Lookup.ServerAddress = ServerAddress;
                        Lookup.ModuleName    = Reader.GetString(3);

                        if (IsBlacklisted(Lookup))
                        {
                            continue;
                        }

                        NWGameServer Server = new NWGameServer(MasterServer, ServerAddress);

                        Server.DatabaseId         = ServerId;
                        Server.ExpansionsMask     = (Byte)Reader.GetUInt32(1);
                        Server.BuildNumber        = (UInt16)Reader.GetUInt32(2);
                        Server.ModuleName         = Reader.GetString(3);
                        Server.ServerName         = Reader.GetString(4);
                        Server.ActivePlayerCount  = Reader.GetUInt32(5);
                        Server.MaximumPlayerCount = Reader.GetUInt32(6);
                        Server.LocalVault         = Reader.GetBoolean(7);
                        Server.LastHeartbeat      = Reader.GetDateTime(8);
                        Server.Online             = Reader.GetBoolean(10);
                        Server.PrivateServer      = Reader.GetBoolean(11);
                        Server.ModuleDescription  = Reader.GetString(12);
                        Server.ModuleUrl          = Reader.GetString(13);
                        Server.GameType           = Reader.GetUInt32(14);
                        Server.MinimumLevel       = Reader.GetUInt32(15);
                        Server.MaximumLevel       = Reader.GetUInt32(16);
                        Server.PVPLevel           = Reader.GetUInt32(17);
                        Server.PlayerPause        = Reader.GetBoolean(18);
                        Server.OnePartyOnly       = Reader.GetBoolean(19);
                        Server.ELCEnforced        = Reader.GetBoolean(20);
                        Server.ILREnforced        = Reader.GetBoolean(21);
                        Server.PWCUrl             = Reader.GetString(22);
                        Server.ServerDescription  = Reader.GetString(23);

                        lock (ActiveServerTable)
                        {
                            ActiveServerTable.Add(ServerAddress, Server);
                        }

                        ServersAdded += 1;
                    }
                }

                Logger.Log(LogLevel.Normal, "NWServerTracker.InitializeDatabase(): Read {0} active servers from database.", ServersAdded);
            }
            catch (Exception e)
            {
                Logger.Log(LogLevel.Error, "NWServerTracker.InitializeDatabase(): Exception: {0}", e);
                MasterServer.Stop();
            }
        }
        /// <summary>
        /// This method parses and handles a module load notify message from a
        /// game server.
        /// </summary>
        /// <param name="Parser">Supplies the message parse context.</param>
        /// <param name="Sender">Supplies the game server address.</param>
        /// <param name="Socket">Supplies the associated socket descriptor
        /// upon which the message was received.</param>
        private void OnRecvMstModuleLoadNotify(ExoParseBuffer Parser, IPEndPoint Sender, SocketInfo Socket)
        {
            Byte ExpansionsMask;
            string ModuleName;

            if (!Parser.ReadBYTE(out ExpansionsMask))
                return;
            if (!Parser.ReadSmallString(out ModuleName, 16))
                return;

            //
            // Query for whether the sender is blacklisted and drop the message
            // if so.
            //

            BlacklistLookup Lookup = new BlacklistLookup();

            Lookup.ServerAddress = Sender;
            Lookup.ModuleName = ModuleName;

            if (ServerTracker.IsBlacklisted(Lookup))
                return;

            NWGameServer Server = ServerTracker.LookupServerByAddress(Sender);

            //
            // Record the module load and request an updated player count.
            //

            Server.OnModuleLoad(ExpansionsMask, ModuleName);
            RefreshServerStatus(Sender);

            Logger.Log(LogLevel.Verbose, "NWMasterServer.OnRecvMstModuleLoadNotify(): Server {0} ModuleName={1} ExpansionsMask={2}.", Sender, ModuleName, ExpansionsMask);
        }
        /// <summary>
        /// This method parses and handles a server startup notify message from
        /// a game server.
        /// </summary>
        /// <param name="Parser">Supplies the message parse context.</param>
        /// <param name="Sender">Supplies the game server address.</param>
        /// <param name="Socket">Supplies the associated socket descriptor
        /// upon which the message was received.</param>
        private void OnRecvMstStartupNotify(ExoParseBuffer Parser, IPEndPoint Sender, SocketInfo Socket)
        {
            Byte Platform;
            UInt16 BuildNumber;
            Byte Unknown0; // 0
            Byte Unknown1; // 0
            Byte Unknown2; // 1
            Byte Unknown3; // 0
            Byte Unknown4; // 3

            if (!Parser.ReadBYTE(out Platform))
                return;
            if (!Parser.ReadWORD(out BuildNumber))
                return;
            if (!Parser.ReadBYTE(out Unknown0))
                return;
            if (!Parser.ReadBYTE(out Unknown1))
                return;
            if (!Parser.ReadBYTE(out Unknown2))
                return;
            if (!Parser.ReadBYTE(out Unknown3))
                return;
            if (!Parser.ReadBYTE(out Unknown4))
                return;

            //
            // Query for whether the sender is blacklisted and drop the message
            // if so.
            //

            BlacklistLookup Lookup = new BlacklistLookup();

            Lookup.ServerAddress = Sender;

            if (ServerTracker.IsBlacklisted(Lookup))
                return;

            NWGameServer Server = ServerTracker.LookupServerByAddress(Sender);

            //
            // Record the server startup.
            //

            Server.OnStartupNotify(Platform, BuildNumber);
            Logger.Log(LogLevel.Verbose, "NWMasterServer.OnRecvMstStartupNotify(): Server {0} Platform={1} BuildNumber={2}.", Sender, (char)Platform, BuildNumber);
        }
        /// <summary>
        /// This method parses a server info response from a game server.
        /// </summary>
        /// <param name="Parser">Supplies the message parser context.</param>
        /// <param name="Sender">Supplies the game server address.</param>
        /// <param name="Socket">Supplies the associated socket descriptor
        /// upon which the message was received.</param>
        private void OnRecvServerInfoResponse(ExoParseBuffer Parser, IPEndPoint Sender, SocketInfo Socket)
        {
            UInt16 DataPort;
            Byte Reserved; // 0xFC
            Byte HasPlayerPassword;
            Byte MinLevel;
            Byte MaxLevel;
            Byte ActivePlayers;
            Byte MaximumPlayers;
            Byte IsLocalVault;
            Byte PVPLevel;
            Byte IsPlayerPauseAllowed;
            Byte IsOnePartyOnly;
            Byte IsELC;
            Byte HasILR;
            Byte ExpansionsMask;
            string ModuleName;
            string BuildNumber;
            ServerInfo Info = new ServerInfo();

            if (!Parser.ReadWORD(out DataPort))
                return;
            if (!Parser.ReadBYTE(out Reserved))
                return;

            if (Mode == GameMode.NWN2)
            {
                if (Reserved != 0xFC)
                    return;
            }
            else
            {
                if (Reserved != 0xFD)
                    return;
            }

            if (!Parser.ReadBYTE(out HasPlayerPassword))
                return;
            if (!Parser.ReadBYTE(out MinLevel))
                return;
            if (!Parser.ReadBYTE(out MaxLevel))
                return;
            if (!Parser.ReadBYTE(out ActivePlayers))
                return;
            if (!Parser.ReadBYTE(out MaximumPlayers))
                return;
            if (!Parser.ReadBYTE(out IsLocalVault))
                return;
            if (!Parser.ReadBYTE(out PVPLevel))
                return;
            if (!Parser.ReadBYTE(out IsPlayerPauseAllowed))
                return;
            if (!Parser.ReadBYTE(out IsOnePartyOnly))
                return;
            if (!Parser.ReadBYTE(out IsELC))
                return;
            if (!Parser.ReadBYTE(out HasILR))
                return;
            if (!Parser.ReadBYTE(out ExpansionsMask))
                return;
            if (!Parser.ReadSmallString(out ModuleName))
                return;

            if (Mode == GameMode.NWN2)
            {
                if (!Parser.ReadSmallString(out BuildNumber))
                    return;
            }
            else
            {
                BuildNumber = "0";
            }

            try
            {
                Info.BuildNumber = Convert.ToUInt16(BuildNumber);
            }
            catch
            {
                Info.BuildNumber = 0;
            }

            //
            // Query for whether the sender is blacklisted and drop the message
            // if so.
            //

            BlacklistLookup Lookup = new BlacklistLookup();

            Lookup.ServerAddress = Sender;
            Lookup.ModuleName = ModuleName;

            if (ServerTracker.IsBlacklisted(Lookup))
                return;

            Info.HasPlayerPassword = (HasPlayerPassword != 0);
            Info.MinLevel = MinLevel;
            Info.MaxLevel = MaxLevel;
            Info.ActivePlayers = ActivePlayers;
            Info.MaximumPlayers = MaximumPlayers;
            Info.IsLocalVault = (IsLocalVault != 0);
            Info.PVPLevel = PVPLevel;
            Info.IsPlayerPauseAllowed = (IsPlayerPauseAllowed != 0);
            Info.IsOnePartyOnly = (IsOnePartyOnly != 0);
            Info.IsELC = (IsELC != 0);
            Info.HasILR = (HasILR != 0);
            Info.ExpansionsMask = ExpansionsMask;
            Info.ModuleName = ModuleName;

            //
            // Look up the server and update the current server information.
            // Since the BNXR reply is used to differentiate between broken
            // NATs and endpoints with multiple servers on the same IP address,
            // carefully check for whether a duplicate server record exists on
            // the server internal port before creating a new server record.
            //

            NWGameServer Server;

            Server = ServerTracker.LookupServerByAddress(Sender);

            if (Mode != GameMode.NWN2)
                Info.BuildNumber = Server.BuildNumber;

            Server.OnServerInfoUpdate(Info);

            if (DataPort == (UInt16)Sender.Port)
            {
                //
                // Both internal and external ports match; the sender is not
                // likely behind a NAT.  No action is necessary behind the
                // creation of the server record above.
                //
            }
            else
            {
                NWGameServer ServerInternal;
                IPEndPoint InternalAddress = new IPEndPoint(Sender.Address, (int)DataPort);
                
                ServerInternal = ServerTracker.LookupServerByAddress(InternalAddress, false);

                if (ServerInternal == null)
                {
                    //
                    // No record of a server existing at the internal address
                    // is yet known.  Proceed to create the server record at
                    // the external address (as was already performed above).
                    //
                }
                else
                {
                    //
                    // A record exists for both internal and external
                    // addresses for the server.  If the configuration values
                    // between both servers are the same, then mark the
                    // external address version as offline and prefer the
                    // internal server address as authoritative (since it must
                    // be globally reachable for a response to have been
                    // received).
                    //

                    if (ServerInternal.CheckForNATDuplicate(Server))
                    {
                        Logger.Log(LogLevel.Normal, "NWMasterServer.OnRecvServerInfoResponse(): Removing NAT duplicate server {0} in preference of server {1}.", Sender, InternalAddress);
                        return;
                    }
                }
            }

            Logger.Log(LogLevel.Verbose, "NWMasterServer.OnRecvServerInfoResponse(): Server {0} has {1}/{2} players ({3}).", Sender, Info.ActivePlayers, Info.MaximumPlayers,
                 Info.ModuleName);
        }
        /// <summary>
        /// Prepare the database, creating tables (if they did not already
        /// exist).
        /// </summary>
        private void InitializeDatabase()
        {
            uint ServersAdded;

            if (String.IsNullOrEmpty(MasterServer.ConnectionString))
                return;

            try
            {
                MasterServer.ExecuteQueryNoReader(
            @"CREATE TABLE IF NOT EXISTS `game_servers` (
            `game_server_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
            `product_id` int(10) UNSIGNED NOT NULL,
            `expansions_mask` int(10) UNSIGNED NOT NULL,
            `build_number` int(10) UNSIGNED NOT NULL,
            `module_name` varchar(32) NOT NULL,
            `server_name` varchar(256) NOT NULL,
            `active_player_count` int(10) UNSIGNED NOT NULL,
            `maximum_player_count` int(10) UNSIGNED NOT NULL,
            `local_vault` bool NOT NULL,
            `last_heartbeat` datetime NOT NULL,
            `server_address` varchar(128) NOT NULL,
            `online` bool NOT NULL,
            `private_server` bool NOT NULL,
            `module_description` varchar(256) NOT NULL,
            `module_url` varchar(256) NOT NULL,
            `game_type` int(10) UNSIGNED NOT NULL,
            `minimum_level` int(10) UNSIGNED NOT NULL,
            `maximum_level` int(10) UNSIGNED NOT NULL,
            `pvp_level` int(10) UNSIGNED NOT NULL,
            `player_pause` bool NOT NULL,
            `one_party_only` bool NOT NULL,
            `elc_enforced` bool NOT NULL,
            `ilr_enforced` bool NOT NULL,
            `pwc_url` varchar(256) NOT NULL,
            `server_description` varchar(256) NOT NULL,
            `game_server_group_id` int(10) UNSIGNED,
            PRIMARY KEY (`game_server_id`),
            UNIQUE KEY (`product_id`, `server_address`),
            INDEX (`product_id`, `online`),
            INDEX (`product_id`, `online`, `server_name`),
            INDEX (`product_id`, `online`, `module_name`),
            INDEX (`product_id`, `online`, `game_type`),
            INDEX (`product_id`, `online`, `game_server_group_id`)
            )");

                MasterServer.ExecuteQueryNoReader(
            @"CREATE TABLE IF NOT EXISTS `game_server_groups` (
            `game_server_group_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
            `product_id` int(10) UNSIGNED NOT NULL,
            `group_name` varchar(128) NOT NULL,
            `global_user_counts` bool NOT NULL,
            PRIMARY KEY (`game_server_group_id`),
            UNIQUE KEY (`product_id`, `group_name`)
            )");

                MasterServer.ExecuteQueryNoReader(
            @"CREATE TABLE IF NOT EXISTS `pending_game_servers` (
            `pending_game_server_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
            `product_id` int(10) UNSIGNED NOT NULL,
            `server_address` varchar(128) NOT NULL,
            PRIMARY KEY (`pending_game_server_id`),
            UNIQUE KEY (`product_id`, `server_address`)
            )");

                MasterServer.ExecuteQueryNoReader(
            @"CREATE TABLE IF NOT EXISTS `client_extension_update` (
            `update_id` int(10) UNSIGNED NOT NULL,
            `product_id` int(10) UNSIGNED NOT NULL,
            `update_message` varchar(4096) NOT NULL,
            `update_url` varchar(4096) NOT NULL,
            `update_info_url` varchar(4096) NOT NULL,
            `update_version` varchar(128) NOT NULL,
            `update_motd` varchar(4096) NOT NULL,
            PRIMARY KEY (`update_id`)
            )");

                MasterServer.ExecuteQueryNoReader(
            @"CREATE TABLE IF NOT EXISTS `stat_counters` (
            `stat_counter_name` varchar(64) NOT NULL,
            `stat_counter_value` int(10) UNSIGNED NOT NULL,
            `stat_counter_last_update` datetime NOT NULL,
            PRIMARY KEY (`stat_counter_name`)
            )");

                MasterServer.ExecuteQueryNoReader(
            @"CREATE TABLE IF NOT EXISTS `blacklist_entries` (
            `blacklist_entry_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
            `product_id` int(10) UNSIGNED NOT NULL,
            `blacklist_entry_type` int(10) UNSIGNED NOT NULL,
            `blacklist_entry_match` varchar(128) NOT NULL,
            PRIMARY KEY (`blacklist_entry_id`)
            )");

                string Query = String.Format(
            @"SELECT `game_server_id`,
            `expansions_mask`,
            `build_number`,
            `module_name`,
            `server_name`,
            `active_player_count`,
            `maximum_player_count`,
            `local_vault`,
            `last_heartbeat`,
            `server_address`,
            `online`,
            `private_server`,
            `module_description`,
            `module_url`,
            `game_type`,
            `minimum_level`,
            `maximum_level`,
            `pvp_level`,
            `player_pause`,
            `one_party_only`,
            `elc_enforced`,
            `ilr_enforced`,
            `pwc_url`,
            `server_description`
            FROM `game_servers`
            WHERE `product_id` = {0}
            AND `online` = true",
                    MasterServer.ProductID);

                RefreshBlacklist();

                ServersAdded = 0;
                using (MySqlDataReader Reader = MasterServer.ExecuteQuery(Query))
                {
                    while (Reader.Read())
                    {
                        uint ServerId = Reader.GetUInt32(0);
                        string Hostname = Reader.GetString(9);
                        int i = Hostname.IndexOf(':');
                        IPEndPoint ServerAddress;

                        if (i == -1)
                        {
                            Logger.Log(LogLevel.Error, "NWServerTracker.InitializeDatabase(): Server {0} has invalid hostname '{1}'.",
                                ServerId,
                                Hostname);
                            continue;
                        }

                        try
                        {
                            ServerAddress = new IPEndPoint(
                                IPAddress.Parse(Hostname.Substring(0, i)),
                                Convert.ToInt32(Hostname.Substring(i + 1)));
                        }
                        catch (Exception e)
                        {
                            Logger.Log(LogLevel.Error, "NWServerTracker.InitializeDatabase(): Error initializing hostname {0} for server {1}: Exception: {2}",
                                Hostname,
                                ServerId,
                                e);
                            continue;
                        }

                        //
                        // Query for whether the server is blacklisted and do
                        // not re-list it if so.
                        //

                        BlacklistLookup Lookup = new BlacklistLookup();

                        Lookup.ServerAddress = ServerAddress;
                        Lookup.ModuleName = Reader.GetString(3);

                        if (IsBlacklisted(Lookup))
                            continue;

                        NWGameServer Server = new NWGameServer(MasterServer, ServerAddress);

                        Server.DatabaseId = ServerId;
                        Server.ExpansionsMask = (Byte)Reader.GetUInt32(1);
                        Server.BuildNumber = (UInt16)Reader.GetUInt32(2);
                        Server.ModuleName = Reader.GetString(3);
                        Server.ServerName = Reader.GetString(4);
                        Server.ActivePlayerCount = Reader.GetUInt32(5);
                        Server.MaximumPlayerCount = Reader.GetUInt32(6);
                        Server.LocalVault = Reader.GetBoolean(7);
                        Server.LastHeartbeat = Reader.GetDateTime(8);
                        Server.Online = Reader.GetBoolean(10);
                        Server.PrivateServer = Reader.GetBoolean(11);
                        Server.ModuleDescription = Reader.GetString(12);
                        Server.ModuleUrl = Reader.GetString(13);
                        Server.GameType = Reader.GetUInt32(14);
                        Server.MinimumLevel = Reader.GetUInt32(15);
                        Server.MaximumLevel = Reader.GetUInt32(16);
                        Server.PVPLevel = Reader.GetUInt32(17);
                        Server.PlayerPause = Reader.GetBoolean(18);
                        Server.OnePartyOnly = Reader.GetBoolean(19);
                        Server.ELCEnforced = Reader.GetBoolean(20);
                        Server.ILREnforced = Reader.GetBoolean(21);
                        Server.PWCUrl = Reader.GetString(22);
                        Server.ServerDescription = Reader.GetString(23);

                        lock (ActiveServerTable)
                        {
                            ActiveServerTable.Add(ServerAddress, Server);
                        }

                        ServersAdded += 1;
                    }
                }

                Logger.Log(LogLevel.Normal, "NWServerTracker.InitializeDatabase(): Read {0} active servers from database.", ServersAdded);
            }
            catch (Exception e)
            {
                Logger.Log(LogLevel.Error, "NWServerTracker.InitializeDatabase(): Exception: {0}", e);
                MasterServer.Stop();
            }
        }
        /// <summary>
        /// Perform a blacklist query.
        /// </summary>
        /// <param name="Lookup">Supplies the query input parameters.</param>
        /// <returns>True if the query matches a blacklist entry.</returns>
        public bool IsBlacklisted(BlacklistLookup Lookup)
        {
            //
            // Locally capture the current blacklist and sweep through the list
            // searching for a match.
            //

            var LocalBlacklist = Blacklist;

            foreach (BlacklistEntry Entry in LocalBlacklist)
            {
                if (Lookup.ServerAddress != null && Entry.IsBlacklistMatched(Lookup.ServerAddress.ToString(), BlacklistEntry.BlacklistType.BlacklistTypeServerAddress))
                    return true;
                if (Lookup.ModuleName != null && Entry.IsBlacklistMatched(Lookup.ModuleName, BlacklistEntry.BlacklistType.BlacklistTypeModuleName))
                    return true;
            }

            return false;
        }