public static IEnumerable<GameServer> GetGameList(string masterServerUrl)
        {
            var wc = new WebClient();
            var data = wc.DownloadData(masterServerUrl + "list.php");
            var str = Encoding.UTF8.GetString(data);

            var yaml = MiniYaml.FromString(str);
            return yaml.Select(a => { var gs = new GameServer(); FieldLoader.Load(gs, a.Value); return gs; })
                .Where(gs => gs.Address != null);
        }
        void RefreshServerList(IEnumerable<GameServer> games)
        {
            var r = Widget.RootWidget;
            var bg = r.GetWidget("JOINSERVER_BG");

            if (bg == null) // We got a MasterServer reply AFTER the browser is gone, just return to prevent crash - Gecko
                return;

            var sl = bg.GetWidget<ListBoxWidget>("SERVER_LIST");

            sl.Children.Clear();
            currentServer = null;

            if (games == null)
            {
                r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true;
                r.GetWidget<LabelWidget>("JOINSERVER_PROGRESS_TITLE").Text = "Failed to contact master server.";
                return;
            }

            if (games.Count() == 0)
            {
                r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true;
                r.GetWidget<LabelWidget>("JOINSERVER_PROGRESS_TITLE").Text = "No games found.";
                return;
            }

            r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = false;

            int offset = ServerTemplate.Bounds.Y;
            int i = 0;
            foreach (var loop in games.Where(g => g.State == 1))	/* only "waiting for players" */
            {
                var game = loop;
                var template = ServerTemplate.Clone() as LabelWidget;
                template.Id = "JOIN_GAME_{0}".F(i);
                template.GetText = () => "   {0} ({1})".F(			/* /8 = hack */
                        game.Name,
                        game.Address);
                template.GetBackground = () => (currentServer == game) ? "dialog2" : null;
                template.OnMouseDown = mi => { currentServer = game; return true; };
                template.Parent = sl;

                template.Bounds = new Rectangle(template.Bounds.X, offset, template.Bounds.Width, template.Bounds.Height);
                template.IsVisible = () => true;
                sl.AddChild(template);

                if (i == 0) currentServer = game;

                offset += template.Bounds.Height;
                sl.ContentHeight += template.Bounds.Height;
                i++;
            }
        }
        void RefreshServerList(IEnumerable<GameServer> games)
        {
            var r = Widget.RootWidget;
            var bg = r.GetWidget("JOINSERVER_BG");

            if (bg == null) // We got a MasterServer reply AFTER the browser is gone, just return to prevent crash - Gecko
                return;

            var sl = bg.GetWidget<ScrollPanelWidget>("SERVER_LIST");

            sl.RemoveChildren();
            currentServer = null;

            if (games == null)
            {
                r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true;
                r.GetWidget<LabelWidget>("JOINSERVER_PROGRESS_TITLE").Text = "Failed to contact master server.";
                return;
            }

            var gamesWaiting = games.Where(g => CanJoin(g));

            if (gamesWaiting.Count() == 0)
            {
                r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true;
                r.GetWidget<LabelWidget>("JOINSERVER_PROGRESS_TITLE").Text = "No games found.";
                return;
            }

            r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = false;

            int i = 0;
            foreach (var loop in gamesWaiting)
            {
                var game = loop;
                var template = ServerTemplate.Clone() as LabelWidget;
                template.Id = "JOIN_GAME_{0}".F(i);
                template.GetText = () => "   {0} ({1})".F(			/* /8 = hack */
                        game.Name,
                        game.Address);
                template.GetBackground = () => (currentServer == game) ? "dialog2" : null;
                template.OnMouseDown = mi => { if (mi.Button != MouseButton.Left) return false; currentServer = game; return true; };
                template.IsVisible = () => true;
                sl.AddChild(template);

                if (i == 0) currentServer = game;
                i++;
            }
        }
        bool CanJoin(GameServer game)
        {
            //"waiting for players"
            if (game.State != 1)
                return false;

            // Mods won't match if there are a different number
            if (Game.CurrentMods.Count != game.Mods.Count())
                return false;

            return game.Mods.All( m => m.Contains('@')) &&  game.Mods.Select( m => Pair.New(m.Split('@')[0], m.Split('@')[1]))
                .All(kv => Game.CurrentMods.ContainsKey(kv.First) &&
                     (kv.Second == "{DEV_VERSION}" || Game.CurrentMods[kv.First].Version == "{DEV_VERSION}" || kv.Second == Game.CurrentMods[kv.First].Version));
        }