private T ReceiveEvent <T>(string[] tokens)
            where T : BuildEventArgs
        {
            var args = BuildWatcher.ParseEventArgs <T>(tokens);

            this.LastMessageTime = args.Time;
            return(args);
        }
        private void ProcessLog(string message)
        {
            var tokens = BuildWatcher.Tokenize(message);

            if (tokens.Length < 2)
            {
                this.IgnoreLog(message);
                return;
            }

            try
            {
                switch (tokens[BuildEventArgs.EventTypeArgIndex])
                {
                case StartBuildEventArgs.StartBuildEventName:
                    this.SessionStarted?.Invoke(this, this.ReceiveEvent <StartBuildEventArgs>(tokens));
                    break;

                case StopBuildEventArgs.StopBuildEventName:
                    this.SessionStopped?.Invoke(this, this.ReceiveEvent <StopBuildEventArgs>(tokens));
                    break;

                case StartJobEventArgs.StartJobEventName:
                    this.JobStarted?.Invoke(this, this.ReceiveEvent <StartJobEventArgs>(tokens));
                    break;

                case FinishJobEventArgs.FinishJobEventName:
                    this.JobFinished?.Invoke(this, this.ReceiveEvent <FinishJobEventArgs>(tokens));
                    break;

                case ReportProgressEventArgs.ReportProgressEventName:
                    this.ReportProgress?.Invoke(this, this.ReceiveEvent <ReportProgressEventArgs>(tokens));
                    break;

                case ReportCounterEventArgs.ReportCounterEventName:
                    this.ReportCounter?.Invoke(this, this.ReceiveEvent <ReportCounterEventArgs>(tokens));
                    break;

                default:
                    this.IgnoreLog(message);
                    break;
                }
            }
            catch (ParseException)
            {
                this.IgnoreLog(message);
            }
        }