static MinerRunResult RunMiner(CmdLineParams info)
        {
            //Run the miner process and begin watching it
            MinerRunResult res = MinerRunResult.RES_MR_BAD_PARAMS_DIDNT_RUN;

            try
            {
                Process proc = new Process();
                proc.StartInfo.FileName = info.strMinerExePath;

                if (info.arrMinerCmdParams.Count > 0)
                {
                    //Make command line
                    string strCmdLn = "";

                    foreach (string strCmd in info.arrMinerCmdParams)
                    {
                        if (!string.IsNullOrEmpty(strCmdLn))
                        {
                            strCmdLn += " ";
                        }

                        if (strCmd.IndexOf(' ') == -1)
                        {
                            strCmdLn += strCmd;
                        }
                        else
                        {
                            strCmdLn += "\"" + strCmd + "\"";
                        }
                    }

                    proc.StartInfo.Arguments       = strCmdLn;
                    proc.StartInfo.UseShellExecute = false;
                    proc.StartInfo.CreateNoWindow  = true;

                    proc.StartInfo.RedirectStandardOutput = true;
                    proc.StartInfo.RedirectStandardError  = true;

                    proc.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
                    {
                        try
                        {
                            DataReceivedFromMiner(e.Data, info);
                        }
                        catch (Exception ex)
                        {
                            //Failed
                            gEventLog.logMessage(EventLogMsgType.ELM_TYP_Error, "EXCEPTION_2: " + ex.ToString());
                            OutputConsoleError("EXCEPTION_2: " + ex.ToString());
                        }
                    });

                    proc.ErrorDataReceived += new DataReceivedEventHandler((sender, e) =>
                    {
                        try
                        {
                            DataReceivedFromMiner(e.Data, info);
                        }
                        catch (Exception ex)
                        {
                            //Failed
                            gEventLog.logMessage(EventLogMsgType.ELM_TYP_Error, "EXCEPTION_3: " + ex.ToString());
                            OutputConsoleError("EXCEPTION_3: " + ex.ToString());
                        }
                    });


                    //Start the process
                    gWS.setMinerProcessClass(proc, true);
                    proc.Start();

                    //Make the miner process exit with ours
                    AttachChildProcessToThisProcess(proc);


                    int nPID = proc.Id;
                    gEventLog.logMessage(EventLogMsgType.ELM_TYP_Information, "Miner started (PID=" + nPID + ") ... with CMD: " + strCmdLn);

                    proc.BeginErrorReadLine();
                    proc.BeginOutputReadLine();
                    proc.WaitForExit();

                    //Get exit code & remember it
                    uint nExitCd = (uint)proc.ExitCode;
                    gWS.setLastMinerExitTimeUTC(nExitCd);

                    gEventLog.logMessage(EventLogMsgType.ELM_TYP_Error, "Miner process (PID=" + nPID + ") has exited with error code 0x" + nExitCd.ToString("X"));

                    OutputConsoleError("WARNING: Miner has exited with error code 0x" + nExitCd.ToString("X") + " ....");

                    res = MinerRunResult.RES_MR_MINER_EXITED;
                }
                else
                {
                    //Error
                    OutputConsoleError("ERROR: Not enough parameters to start a miner");

                    res = MinerRunResult.RES_MR_BAD_PARAMS_DIDNT_RUN;
                }
            }
            catch (Exception ex)
            {
                //Failed
                gEventLog.logMessage(EventLogMsgType.ELM_TYP_Error, "EXCEPTION_1: " + ex.ToString());
                OutputConsoleError("EXCEPTION_1: " + ex.ToString());
                res = MinerRunResult.RES_MR_EXCEPTION;
            }

            return(res);
        }
        static void MinerRunningLoop(CmdLineParams info)
        {
            //Loop that runs the miner and watches its performance

            Random rnd = new Random();

            for (;;)
            {
                int nmsWait;

                //Run the miner
                MinerRunResult res = RunMiner(info);

                if (res == MinerRunResult.RES_MR_BAD_PARAMS_DIDNT_RUN)
                {
                    gEventLog.logMessage(EventLogMsgType.ELM_TYP_Critical, "Quitting watch app due to unrecoverable error!");
                    OutputConsoleError("CRITICAL ERROR: Quitting watch app due to unrecoverable error!");
                    return;
                }
                else if (res == MinerRunResult.RES_MR_EXCEPTION)
                {
                    //Wait for some time
                    nmsWait = rnd.Next(10 * 1000, 60 * 1000);
                }
                else if (res == MinerRunResult.RES_MR_MINER_EXITED)
                {
                    //Wait for some time
                    nmsWait = rnd.Next(10 * 1000, 30 * 1000);
                }
                else
                {
                    //Some other value
                    gEventLog.logMessage(EventLogMsgType.ELM_TYP_Critical, "Quitting watch app due to unknown error! err=" + res);
                    OutputConsoleError("CRITICAL ERROR: Quitting watch app due to unknown error!");
                    return;
                }


                //Wait before restarting
                Console.WriteLine("Waiting for " + nmsWait / 1000 + " sec before restarting the miner...");
                Thread.Sleep(nmsWait);

                //Log message
                int  nExitCode;
                uint nNumStarted;
                gWS.getLastMinerExitTimeUTC(out nExitCode, out nNumStarted);
                gEventLog.logMessage(EventLogMsgType.ELM_TYP_Warning, "MINER RESTART (number " + nNumStarted + ") after " + nmsWait / 1000 + " sec delay. Reason=" + res +
                                     ", exitCode=0x" + nExitCode.ToString("X"));


                //See if we've restarted too many times (and if we're allowed to reboot)
                if (info.nMaxAllowedMinerRestartsBeforeReboot > 0 &&
                    nNumStarted > info.nMaxAllowedMinerRestartsBeforeReboot)
                {
                    //Need to reboot the system
                    gEventLog.logMessage(EventLogMsgType.ELM_TYP_Error, "Will attempt to REBOOT the rig after " + nNumStarted + " miner restarts");
                    OutputConsoleError("CRITICAL: Will attempt to REBOOT the rig after " + nNumStarted + " miner restarts");

                    Thread.Sleep(3 * 1000);

                    //Force reboot
                    rebootRig(true, "After " + nNumStarted + "attempts to restart miner process");

                    break;
                }
            }
        }