private void BWDoWork(object sender, DoWorkEventArgs ex)
        {
            SiteProfile profile = (SiteProfile)ex.Argument;

            string arguments = profile.GetArguments();
            FakeIP fakeip    = FakeIP.From(arguments); // fake ip
            FakeUA fakeua    = FakeUA.From(arguments); // fake ua

            // report begin state
            bgWork.ReportProgress(-1, null);

            for (int i = 1; i <= profile.PlayTimes; i++)
            {
                /** Report progress, states.
                 * progress is indicated in e.UserState (value: progressFullness)
                 */
                double progressFullness = (double)i / profile.PlayTimes;

                try
                {
                    string response = PlaySite(arguments, fakeip, fakeua, profile.IsReadResponse);
                    bgWork.ReportProgress(100, new object[] { progressFullness, i, response });
                }
                catch (Exception err)
                {
                    bgWork.ReportProgress(100, new object[] { progressFullness, i, err.Message });
                    return;
                }

                /** No Sleep. Check CancellationPending and continue
                 */
                if (profile.DelayMin <= 0)
                {
                    if (bgWork.CancellationPending)
                    {
                        return;
                    }
                    else
                    {
                        continue;
                    }
                }

                /** Sleep. Check CancellationPending every 100ms
                 */
                int sleep_count_100ms = profile.DelayMax > profile.DelayMin ?
                                        random.Next(profile.DelayMin, profile.DelayMax) * 10
                    : profile.DelayMin * 10;

                while (sleep_count_100ms-- > 0)
                {
                    System.Threading.Thread.Sleep(100);

                    if (bgWork.CancellationPending)
                    {
                        return;
                    }
                }
            }
        }
        private string PlaySite(string arguments, FakeIP fakeip, FakeUA fakeua, bool readReponse)
        {
            // fake ip
            if (fakeip != null)
            {
                string ip;
                if (fakeip.FakeMethod == FakeIP.Method.Pick)
                {
                    ip = IPManager.GetRandom()?.IP;
                }
                else
                {
                    ip = IPManager.GetGenerate();
                }

                if (string.IsNullOrWhiteSpace(ip))
                {
                    throw new Exception(sr_fake_ip_error);
                }
                else
                {
                    arguments = arguments.Replace(fakeip.Replace, ip);
                }
            }

            // fake ua
            if (fakeua != null)
            {
                string ua = UAManager.GetRandom()?.Value;
                if (string.IsNullOrWhiteSpace(ua))
                {
                    throw new Exception(sr_fake_ua_error);
                }
                else
                {
                    arguments = arguments.Replace(fakeua.Replace, ua);
                }
            }

            // curl process
            Process process = new Process()
            {
                StartInfo =
                {
                    FileName               = Utility.CurlManager.PathCurlExe,
                    Arguments              = arguments,
                    WorkingDirectory       = App.PathCurl,
                    CreateNoWindow         = true,
                    UseShellExecute        = false,
                    RedirectStandardOutput = readReponse,
                },
            };

            string response;

            try
            {
                process.Start();

                response = process.StartInfo.RedirectStandardOutput ?
                           process.StandardOutput.ReadToEnd() :
                           $"{sr_complete} {DateTime.Now.ToString("yyyy.MM.dd-HH:mm:ss")}";
                process.WaitForExit();
            }
            catch
            {
                response = $"{sr_failed} {DateTime.Now.ToString("yyyy.MM.dd-HH:mm:ss")}";
            }
            finally
            {
                process.Dispose();
            }

            return(response);
        }