private async void MainForm_Load(object sender, EventArgs e)
        {
            await Task.Delay(10);

            // Load online data
            var data = await FetchOnlineDataAsync();

            lblAbout.Text = data.AboutText;

            // Order the list to get the featured servers to the top, putting bancho back at index 0
            m_servers.Add(Server.BanchoServer);
            m_servers.AddRange(data.Servers.Where(x => x.IsFeatured));
            m_servers.AddRange(data.Servers.Where(x => !x.IsFeatured));
            m_servers.Add(Server.LocalhostServer);

            lblCurrentServer.Text = "Updating icon cache...";
            Application.DoEvents();

            // Check if servers which icon is in cache no longer exist
            foreach (string icon in Directory.GetFiles(m_iconCacheFolder, "*.png", SearchOption.TopDirectoryOnly))
            {
                string name = Path.GetFileNameWithoutExtension(icon);
                if (!m_servers.Any(x => x.ServerName == name))
                {
                    File.Delete(icon);
                }
            }

            // Check for servers which icons arent in cache yet
            foreach (Server server in m_servers)
            {
                if (!File.Exists(m_iconCacheFolder + $@"\{server.ServerName}.png") && !string.IsNullOrEmpty(server.IconUrl))
                {
                    lblCurrentServer.Text = $"Downloading icon of {server.ServerName}...";
                    Application.DoEvents();
                    Image icon = await DownloadImageAsync(server.IconUrl);

                    icon.Save(m_iconCacheFolder + $@"\{server.ServerName}.png");
                    icon.Dispose();
                }
            }

            // Load icons from cache
            foreach (Server server in m_servers)
            {
                if (File.Exists(m_iconCacheFolder + $@"\{server.ServerName}.png"))
                {
                    using (MemoryStream ms = new MemoryStream(File.ReadAllBytes(m_iconCacheFolder + $@"\{server.ServerName}.png")))
                        server.Icon = Image.FromStream(ms);
                }
            }

            // Create .ico files for shortcuts
            foreach (Server server in m_servers)
            {
                if (server.Icon != null)
                {
                    using (FileStream fs = File.OpenWrite(m_iconCacheFolder + $@"\{server.ServerName}.ico"))
                        using (MemoryStream ms = new MemoryStream((byte[])new ImageConverter().ConvertTo(server.Icon, typeof(byte[]))))
                            ImagingHelper.ConvertToIcon(ms, fs, 48, true);
                }
            }

            //Adds all servers to combo box
            foreach (Server server in m_servers)
            {
                string name = server.ServerName;
                if (server.IsFeatured)
                {
                    name = "⭐" + name + "⭐";
                }
                cmbbxServer.Items.Add(name);
            }

            bool newVersionAvailable = await VersionChecker.NewVersionAvailable();

            btnUpdateAvailable.Visible = newVersionAvailable;

            lblClearIconCache.Enabled = true;
            lblCreateShortcut.Show();

            UpdateServerUI();

            osuWatcher.Start();
        }
        private async void MainForm_Load(object sender, EventArgs e)
        {
            // Hide the connect button, show the loading button to make the user clear that the servers are being fetched
            btnConnect.Visible  = false;
            pctrLoading.Visible = true;
            Application.DoEvents();

            await Task.Delay(1);

            // Check the state of the current version
            VersionState vs = await VersionChecker.GetCurrentState();

            if (vs == VersionState.BLACKLISTED)
            {
                // If the current version is blacklisted, prevent the user from using it.
                MessageBox.Show($"Your current version ({VersionChecker.CurrentVersion}) is blacklisted.\r\n\r\nThis can happen when the version contains security flaws or other things that could interrupt a good user experience.\r\n\r\nPlease download the newest version of the switcher from its website. (github.com/minisbett/ultimate-osu-server-switcher/releases).", "Ultimate Osu Server Switcher", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Environment.Exit(0);
                return;
            }
            else if (vs == VersionState.MAINTENANCE)
            {
                // If the switcher is in maintenance, also prevent the user from using it.
                MessageBox.Show("The switcher is currently hold in maintenance mode which means that the switcher is currently not available.\r\n\r\nJoin our discord server for more informations.\r\nThe discord server and be found on our github page.", "Ultimate Osu Server Switcher", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Environment.Exit(0);
                return;
            }
            else if (vs == VersionState.OUTDATED)
            {
                // Show the user a message that a new version is available if the current switcher is outdated.
                MessageBox.Show($"Your switcher version ({VersionChecker.CurrentVersion}) is outdated.\r\nA newer version ({await VersionChecker.GetNewestVersion()}) is available.\r\n\r\nYou can download it from our github page.", "Ultimate Osu Server Switcher", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }


            lblInfo.Text = "Fetching mirrors...";
            Application.DoEvents();

            // Try to load online data and verify servers
            List <Mirror> mirrors = null;

            try
            {
                // Download the mirror data from github and deserialize it into a mirror list
                mirrors = JsonConvert.DeserializeObject <List <Mirror> >(await WebHelper.DownloadStringAsync(Urls.Mirrors));
            }
            catch
            {
                // If it was not successful, github may cannot currently be reached or I made a mistake in the json data.
                MessageBox.Show("Error whilst parsing the server mirrors from GitHub!\r\nPlease make sure you can connect to www.github.com in your browser.\r\n\r\nIf this issue persists, please visit our discord. You can find the invite link on our GitHub Page (minisbett/ultimate-osu-server-switcher)", "Ultimate Osu Server Switcher", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Application.Exit();
                return;
            }

            imgLoadingBar.Maximum = mirrors.Count;
            // Try to load all servers
            List <Server> servers = new List <Server>();

            foreach (Mirror mirror in mirrors)
            {
                lblInfo.Text = $"Parsing mirror {mirror.Url}";
                Application.DoEvents();
                Server server = null;
                // Try to serialize the mirror into a server
                try
                {
                    // Download the data from the mirror and try to parse it into a server object.
                    server = JsonConvert.DeserializeObject <Server>(await WebHelper.DownloadStringAsync(mirror.Url));
                }
                catch
                {
                    // If the cast was not successful (invalid json) or the mirror could not be reached, skip the mirror
                    continue;
                }
                // Forward mirror variables to the server
                server.IsFeatured = mirror.Featured;
                server.UID        = mirror.UID;
                lblInfo.Text      = $"Parsing mirror {mirror.Url} ({server.ServerName})";
                Application.DoEvents();

                // Check if UID is 6 letters long (If not I made a mistake)
                if (server.UID.Length != 6)
                {
                    continue;
                }

                // Check if the UID is really unique (I may accidentally put the same uid for two servers)
                if (servers.Any(x => x.UID == server.UID))
                {
                    continue;
                }

                // Check if everything is set
                if (server.ServerName == null ||
                    server.IP == null ||
                    server.IconUrl == null ||
                    server.CertificateUrl == null ||
                    server.DiscordUrl == null)
                {
                    continue;
                }

                // Check if server name length is valid (between 3 and 24)
                if (server.ServerName.Replace(" ", "").Length < 3 || server.ServerName.Length > 24)
                {
                    continue;
                }
                // Check if it neither start with a space, nor end
                if (server.ServerName.StartsWith(" "))
                {
                    continue;
                }
                if (server.ServerName.EndsWith(" "))
                {
                    continue;
                }
                // // Only a-zA-Z0-9 ! is allowed
                if (!Regex.Match(server.ServerName.Replace("!", "").Replace(" ", ""), "^\\w+$").Success)
                {
                    continue;
                }
                // Double spaces are invalid because its hard to tell how many spaces there are
                // (One server could be named test 123 and the other test  123)
                if (server.ServerName.Replace("  ", "") != server.ServerName)
                {
                    continue;
                }
                // Check if the server fakes a hardcoded server
                if (Server.StaticServers.Any(x => x.ServerName == server.ServerName))
                {
                    continue;
                }

                // Check if the server ip is formatted correctly
                if (!Regex.IsMatch(server.IP, @"^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$"))
                {
                    continue;
                }

                // Check if that server name already exists (if so, prioritize the first one)
                if (servers.Any(x => x.ServerName.ToLower().Replace(" ", "") == server.ServerName.ToLower().Replace(" ", "")))
                {
                    continue;
                }

                // Check if its a real discord invite url
                if (!server.DiscordUrl.Replace("https", "").Replace("http", "").Replace("://", "").StartsWith("discord.gg"))
                {
                    continue;
                }

                // Initialize variables like Certificate and Icon that are downloaded from their urls when
                // all checks are done (IconUrl, CertificateUrl)

                try
                {
                    // Try to parse the certificate from the given url
                    server.Certificate = await WebHelper.DownloadBytesAsync(server.CertificateUrl);

                    server.CertificateThumbprint = new X509Certificate2(server.Certificate).Thumbprint;
                }
                catch // Cerfiticate url not valid or certificate type is not cer (base64 encoded)
                {
                    continue;
                }

                // Check if icon is valid
                try
                {
                    // Download the icon and check if its at least 256x256
                    Image icon = await WebHelper.DownloadImageAsync(server.IconUrl);

                    if (icon.Width < 256 || icon.Height < 256)
                    {
                        continue;
                    }

                    // Scale the image to 256x256
                    server.Icon = new Bitmap(icon, new Size(256, 256));

                    // Add the server to the servers that were successfully parsed and checked
                    servers.Add(server);
                }
                catch // Image could not be downloaded or loaded
                {
                    continue;
                }

                imgLoadingBar.Value++;
            }

            // Load bancho and localhost
            try
            {
                // Download the icon and check if its at least 256x256
                Image icon = await WebHelper.DownloadImageAsync(Server.BanchoServer.IconUrl);

                if (icon.Width >= 256 && icon.Height >= 256)
                {
                    // Add the bancho server
                    Server s = Server.BanchoServer;
                    // Scale the image to 256x256
                    s.Icon = new Bitmap(icon, new Size(256, 256));
                    servers.Add(s);
                }
            }
            catch // Image could not be downloaded or loaded
            {
            }

            try
            {
                // Download the icon and check if its at least 256x256
                Image icon = await WebHelper.DownloadImageAsync(Server.LocalhostServer.IconUrl);

                if (icon.Width >= 256 && icon.Height >= 256)
                {
                    // Add the localhost server
                    Server s = Server.LocalhostServer;
                    // Scale the image to 256x256
                    s.Icon = new Bitmap(icon, new Size(256, 256));
                    servers.Add(s);
                }
            }
            catch // Image could not be downloaded or loaded
            {
            }

            // Sort the servers by priority (first bancho, then featured, then normal, then localhost)
            servers = servers.OrderByDescending(x => x.Priority).ToList();

            // Create .ico files for shortcuts
            foreach (Server server in servers)
            {
                using (FileStream fs = File.OpenWrite(Paths.IconCacheFolder + $@"\{server.UID}.ico"))
                    using (MemoryStream ms = new MemoryStream((byte[])new ImageConverter().ConvertTo(server.Icon, typeof(byte[]))))
                        ImagingHelper.ConvertToIcon(ms, fs, server.Icon.Width, true);
            }

            Switcher.Servers = servers;

            // Enable/Disable the timer depending on if useDiscordRichPresence is true or false
            // Set here because the timer needs to have the servers loaded
            richPresenceUpdateTimer.Enabled = m_settings["useDiscordRichPresence"] == "true";

            // Initialize the current selected server variable
            m_currentSelectedServer = Switcher.GetCurrentServer();
            if (m_currentSelectedServer.IsUnidentified)
            {
                m_currentSelectedServer = Switcher.Servers.First(x => x.UID == "bancho");
            }

            // Hide loading button and loading bar after all mirrors are loaded
            pctrLoading.Visible   = false;
            imgLoadingBar.Visible = false;

            // Show the account manager button because all servers are loaded now
            btnAccountManager.Visible = true;

            // Update the UI
            UpdateUI();
        }