Inheritance: System.Net.WebClient
        public VersionPair CheckUpdates(GameModel model)
        {
            if (model == null) {
                throw new ArgumentException("model argument cannot be null");
            }
            string versionFile = ConfigurationManager.GetLocalVersionFile(model);
            if (File.Exists(ConfigurationManager.GetLocalVersionFile(model))) {
                int verCurrent = -1;
                int verRemote = -1;

                using (StreamReader streamReader = new StreamReader(versionFile)) {
                    verCurrent = GetVersion(streamReader.ReadToEnd());
                }

                using (WebClientEx webClient = new WebClientEx()) {
                    string result;
                    try {
                        result = webClient.DownloadString(ConfigurationManager.GetConfiguration(model).VersionRemoteURL);
                        verRemote = GetVersion(result);
                    } catch {
                        return null;
                    }

                    if (verRemote < 0 || verCurrent < 0) {
                        return null;
                    }
                    return new VersionPair(verCurrent, verRemote);
                }
            }
            return null;
        }
        public bool DownloadUpdates(GameModel model, VersionPair versionPair)
        {
            if (model == null) {
                throw new ArgumentException("model argument cannot be null");
            }
            if (versionPair == null) {
                throw new ArgumentException("versionPair argument cannot be null");
            }
            bool updateSuccess = true;
            double downloadedContentLenght = 0;
            double WholeContentLength = 0;

            Dictionary<int, double> contentLenght = new Dictionary<int, double>();
            try {
                for (int i = versionPair.Local + 1; i <= versionPair.Remote; i++) {
                    double patchSize = GetFileLength(new Uri(string.Format(ConfigurationManager.GetConfiguration(model).PatchRemoteURL, i)));
                    WholeContentLength += patchSize;
                    contentLenght.Add(i, patchSize);
                }
            } catch (WebException) {
                return false;
            }

            for (int i = versionPair.Local + 1; i <= versionPair.Remote; i++) {
                Uri patchUri = new Uri(string.Format(ConfigurationManager.GetConfiguration(model).PatchRemoteURL, i));
                string packageFile = Path.Combine(ConfigurationManager.GetGamePath(model), string.Format("UPDATE{0}.zip", i));

                OnStatusChanged(UpdateStatusEventArgs.Stage.DOWNLOADING, i, versionPair.Remote, downloadedContentLenght, WholeContentLength, 0, 100);
                double CurrentContentLength = 0;
                if (!contentLenght.TryGetValue(i, out CurrentContentLength)) {
                    updateSuccess = false;
                    break;
                }

                int downloadAttempts = 5;
                bool patchSuccess = false;
                while (downloadAttempts > 0 && !patchSuccess) {
                    try {
                        if (File.Exists(packageFile)) {
                            File.Delete(packageFile);
                        }
                    } catch {
                        updateSuccess = false;
                        break;
                    }

                    using (WebClientEx webClient = new WebClientEx()) {
                        DownloadProgressChangedEventHandler progressChangedEventHandler = (s, e) => {
                            double dataReceived = (e.BytesReceived / (1024.0 * 1024.0));
                            double dataTotal = (e.TotalBytesToReceive / (1024.0 * 1024.0));
                            OnStatusChanged(UpdateStatusEventArgs.Stage.DOWNLOADING,
                                i, versionPair.Remote,
                                downloadedContentLenght + e.BytesReceived, WholeContentLength,
                                dataReceived, dataTotal);
                        };

                        webClient.DownloadProgressChanged += progressChangedEventHandler;
                        try {
                            webClient.DownloadFileAsync(patchUri, packageFile);
                            while (webClient.IsBusy) {
                                System.Threading.Thread.Sleep(100);
                            }
                            downloadedContentLenght += CurrentContentLength;
                        } catch {
                            downloadAttempts--;
                            continue;
                        } finally {
                            webClient.DownloadProgressChanged -= progressChangedEventHandler;
                        }
                    }
                    if (!ConfigurationManager.CheckUpdateAccess(model)) {
                        updateSuccess = false;
                        break;
                    }
                    if (ExtractUpdate(i, versionPair.Remote,
                        downloadedContentLenght, WholeContentLength,
                        packageFile, ConfigurationManager.GetGamePath(model), true)) {
                        try {
                            string versionFile = ConfigurationManager.GetLocalVersionFile(model);
                            string directory = Path.GetDirectoryName(versionFile);
                            if (!Directory.Exists(directory)) {
                                Directory.CreateDirectory(directory);
                            }
                            File.WriteAllLines(versionFile, new string[] { "[VERSION]", "version=" + i.ToString() });
                        } catch {
                            updateSuccess = false;
                            break;
                        }
                        patchSuccess = true;
                    }
                    downloadAttempts--;
                }
                if (!patchSuccess) {
                    updateSuccess = false;
                    break;
                }
            }
            return updateSuccess;
        }
        public void GetTwitterNewsAPI11(string url)
        {
            TwitterStatuses.Clear();
            if (string.IsNullOrEmpty(url)) {
                TwitterStatuses.Add(new TwitterItemViewModel(LanguageManager) {
                    Title = LanguageManager.Model.NewsTwitterError + ": [ERRCODE 4 - No URL specified]",
                    Date = DateTime.Now
                });
                return;
            }
            Uri link = new Uri(url);
            string response;
            using (WebClient wc = new WebClientEx()) {
                try {
                    response = wc.DownloadString(link);
                } catch (Exception e) {
                    TwitterStatuses.Add(new TwitterItemViewModel(LanguageManager) {
                        Title = LanguageManager.Model.NewsTwitterError + ": " + e.Message + " [ERRCODE 3 - Remote Error]",
                        Date = DateTime.Now
                    });
                    return;
                }
            }

            JArray tList;
            try {
                tList = JArray.Parse(System.Web.HttpUtility.HtmlDecode(response));
            } catch {
                TwitterStatuses.Add(new TwitterItemViewModel(LanguageManager) {
                    Title = LanguageManager.Model.NewsTwitterError + " [ERRCODE 1 - Parse Error]",
                    Date = DateTime.Now
                });
                return;
            }

            List<UserStatus> statuses = new List<UserStatus>();
            List<ProfileImage> profileImages = new List<ProfileImage>();
            List<ProfileImage> currentImage;
            ProfileImage profileImage;
            for (int i = 0; i < tList.Count(); i++) {
                JObject tweet = JObject.Parse(tList[i].ToString());
                UserStatus status = new UserStatus();

                status.UserName = tweet["user"]["name"].ToString();
                status.UserScreenName = tweet["user"]["screen_name"].ToString();
                status.ProfileImageUrl = tweet["user"]["profile_image_url"].ToString();
                var retweet = tweet["retweeted_status"];
                if (retweet != null) {
                    status.UserScreenName = retweet["user"]["name"].ToString();
                    status.UserName = retweet["user"]["screen_name"].ToString();
                    status.RetweetImageUrl = retweet["user"]["profile_image_url"].ToString();
                }

                status.Status = tweet["text"].ToString();
                status.StatusId = tweet["id"].ToString();
                status.StatusDate = ParseDateTime(tweet["created_at"].ToString());

                string profile_image;
                if (status.RetweetImageUrl != null) {
                    profile_image = status.RetweetImageUrl;
                } else {
                    profile_image = status.ProfileImageUrl;
                }

                currentImage = profileImages.FindAll(im => (im.url == profile_image));
                if (currentImage.Count == 0) {
                    profileImage = new ProfileImage();
                    profileImage.url = profile_image;
                    profileImage.bitmap = GetImage(profile_image);
                    if (profileImage.bitmap != null) {
                        profileImages.Add(profileImage);
                    }
                } else {
                    profileImage = currentImage[0];
                }
                status.ProfileImageBitmap = profileImage.bitmap;
                statuses.Add(status);
            }
            foreach (UserStatus status in statuses) {
                TwitterStatuses.Add(new TwitterItemViewModel(LanguageManager) {
                    Title = status.Status,
                    Date = status.StatusDate,
                    Image = status.ProfileImageBitmap,
                    StatusLink = "https://twitter.com/statuses/" + status.StatusId,
                    UserLink = "https://twitter.com/" + status.UserScreenName,
                    UserName = status.UserName
                });
            }
        }
        private BitmapImage GetImage(string url)
        {
            using (WebClient wc = new WebClientEx()) {
                Uri uri = new Uri(url);
                byte[] image_bytes;
                try {
                    image_bytes = wc.DownloadData(uri);
                } catch {
                    return null;
                }

                MemoryStream img_stream = new MemoryStream(image_bytes, 0, image_bytes.Length);
                BitmapImage bitmap = new BitmapImage();
                bitmap.BeginInit();
                bitmap.StreamSource = img_stream;
                bitmap.EndInit();
                bitmap.Freeze();

                return bitmap;
            }
        }
        public string ResolveResource(string folder, string file, string downloadUrl = null)
        {
            string resource = Path.Combine(ResourcesPath, folder, file);
            string resource3rd = Path.Combine(InitFolder(Resources3rdPath, folder), file);
            if (File.Exists(resource)) {
                return resource;
            }
            if (File.Exists(resource3rd)) {
                return resource3rd;
            }

            if (downloadUrl != null) {
                using (WebClientEx webClient = new WebClientEx()) {
                    try {
                        webClient.DownloadFile(downloadUrl, resource3rd);
                    } catch {
                        // fall down
                    }
                }
            }
            return File.Exists(resource3rd) ? resource3rd : null;
        }