private void LoadQlstatsPlayerList(ServerRow row, Action callback = null)
        {
            this.qlstatsPlayerlists[row] = null;
            using (var client = new XWebClient(2000))
            {
                client.Encoding = Encoding.UTF8;

                client.DownloadStringCompleted += (sender, args) =>
                {
                    try
                    {
                        using (var strm = new MemoryStream(Encoding.UTF8.GetBytes(args.Result)))
                        {
                            var playerList = (QlstatsPlayerList)playerListJsonParser.ReadObject(strm);
                            this.qlstatsPlayerlists[row] = playerList;
                            if (playerList.serverinfo != null)
                            {
                                this.skillInfo[row.EndPoint.ToString()] = playerList.serverinfo;
                            }
                            callback?.Invoke();
                        }
                    }
                    catch
                    {
                    }
                };

                client.DownloadStringAsync(new Uri("http://api.qlstats.net/api/server/" + row.EndPoint + "/players"));
            }
        }
        private void LoadQlstatsPersonalRating()
        {
            if (this.Steamworks == null)
            {
                return;
            }
            var steamid = this.Steamworks.GetUserID();

            if (steamid == 0)
            {
                return;
            }
            using (var client = new XWebClient(2000))
            {
                client.DownloadStringCompleted += (sender, args) =>
                {
                    try
                    {
                        using (var strm = new MemoryStream(Encoding.UTF8.GetBytes(args.Result)))
                        {
                            var result = (QlstatsGlickoRating)personalSkillJsonParser.ReadObject(strm);
                            var text   = "\n\nYour personal rating: estimate ± uncertainty:";
                            foreach (var player in result.players)
                            {
                                var gametypes = new[] { "ffa", "ca", "duel", "ctf", "tdm", "ft" };
                                var ratings   = new[] { player.ffa, player.ca, player.duel, player.ctf, player.tdm, player.ft };
                                for (int i = 0; i < gametypes.Length; i++)
                                {
                                    var rating = ratings[i];
                                    if (rating == null)
                                    {
                                        continue;
                                    }
                                    text += $"\n{gametypes[i].ToUpper()}: {rating.r} ± {rating.rd} ({rating.games} games)";
                                }
                                if (gametypes.Length == 0)
                                {
                                    text = "";
                                }
                            }

                            if (this.colSkill?.View?.GridControl == null)
                            {
                                return;
                            }
                            this.colSkill.View.GridControl.BeginInvoke((Action)(() =>
                            {
                                this.colSkill.ToolTip = SkillTooltip + text;
                            }));
                        }
                    }
                    catch
                    {
                    }
                };
                client.DownloadStringAsync(new Uri("http://qlstats.net/glicko/" + steamid));
            }
        }
        private void LoadQlstatsServerRatings()
        {
            using (var client = new XWebClient(2000))
            {
                client.DownloadStringCompleted += (sender, args) =>
                {
                    try
                    {
                        if (args.Error != null)
                        {
                            return;
                        }
                        using (var strm = new MemoryStream(Encoding.UTF8.GetBytes(args.Result)))
                        {
                            var servers = (QlStatsSkillInfo[])serverSkillJsonParser.ReadObject(strm);
                            var dict    = new Dictionary <string, QlStatsSkillInfo>();
                            foreach (var server in servers)
                            {
                                dict[server.server] = server;
                            }
                            this.skillInfo = dict;

                            var view = this.colSkill?.View;
                            var grid = view?.GridControl;
                            if (grid == null)
                            {
                                return;
                            }
                            grid.BeginInvoke((Action)(() =>
                            {
                                for (int i = 0, c = view.RowCount; i < c; i++)
                                {
                                    var row = (ServerRow)view.GetRow(i);
                                    var info = dict.GetValueOrDefault(row.EndPoint.ToString(), null);
                                    if (info != null)
                                    {
                                        row.PlayerCount.Update();
                                    }
                                }
                            }));
                        }
                    }
                    catch
                    {
                    }
                };
                client.DownloadStringAsync(new Uri("http://api.qlstats.net/api/server/skillrating"));
            }
        }
        public void GetAddresses(Region region, IpFilter filter, int maxResults, MasterIpCallback callback)
        {
            try
            {
                using (var client = new XWebClient())
                {
                    var text = client.DownloadString(this.url);
                    if (text == null)
                    {
                        callback(null, null, false);
                        return;
                    }

                    var lines     = text.Split('\n');
                    var endpoints = new List <Tuple <IPEndPoint, ServerInfo> >(lines.Length);
                    int i         = 0;
                    foreach (var line in lines)
                    {
                        if (string.IsNullOrWhiteSpace(line))
                        {
                            continue;
                        }
                        var parts = line.Split(':');
                        if (parts.Length != 2)
                        {
                            continue;
                        }

                        IPAddress addr;
                        int       port;
                        if (IPAddress.TryParse(parts[0], out addr) && int.TryParse(parts[1].TrimEnd(), out port))
                        {
                            endpoints.Add(new Tuple <IPEndPoint, ServerInfo>(new IPEndPoint(addr, port), null));
                            if (++i == maxResults)
                            {
                                break;
                            }
                        }
                    }
                    callback(new ReadOnlyCollection <Tuple <IPEndPoint, ServerInfo> >(endpoints), null, false);
                }
            }
            catch (Exception ex)
            {
                callback(null, ex, false);
            }
        }
        private void ProcessLoop()
        {
            using (var client = new XWebClient(5000))
            {
                while (true)
                {
                    var ip = this.queue.Take();
                    if (ip == null)
                    {
                        break;
                    }

                    bool err   = true;
                    var  ipInt = Ip4Utils.ToInt(ip);
                    try
                    {
                        var url    = string.Format(this.ServiceUrlFormat, ip);
                        var result = client.DownloadString(url);
                        if (result != null)
                        {
                            object           o;
                            Action <GeoInfo> callbacks;
                            lock (cache)
                                callbacks = cache.TryGetValue(ipInt, out o) ? o as Action <GeoInfo> : null;
                            var geoInfo = this.HandleResult(ipInt, result);
                            if (callbacks != null && geoInfo != null)
                            {
                                ThreadPool.QueueUserWorkItem(ctx => callbacks(geoInfo));
                            }
                            err = false;
                        }
                    }
                    catch
                    {
                        // ignore
                    }

                    if (err)
                    {
                        lock (this.cache)
                            this.cache.Remove(ipInt);
                    }
                }
            }
        }