double ReadProcessAddReport( DirectoryInfo DirInfo, FGenericCrashContext NewContext )
		{
			try
			{
				string DumpFileName = null;
				string LogFileName = null;
				string DiagnosticsFileName = "";
				string VideoFileName = null;

				string CrashContextName = "";

				foreach( FileInfo Info in DirInfo.GetFiles() )
				{
					switch( Info.Extension.ToLower() )
					{
					case ".avi":
					case ".mp4":
						VideoFileName = Info.Name;
						break;

					case ".runtime-xml":
						CrashContextName = Info.Name;
						break;

					case ".log":
						LogFileName = Info.Name;
						break;

					case ".txt":
						if (string.Compare( Info.Name, CrashReporterConstants.DiagnosticsFileName, true ) == 0)
						{
							DiagnosticsFileName = Info.Name;
							ReadDiagnosticsFile( NewContext );				
						}
						break;

					case ".dmp":
					case ".mdmp":
						DumpFileName = Info.Name;
						// Check to see if this has been processed locally
						FileInfo DiagnosticsInfo = new FileInfo( Path.Combine( DirInfo.FullName, CrashReporterConstants.DiagnosticsFileName ) );
						if (!DiagnosticsInfo.Exists && !NewContext.HasProcessedData())
						{
							ProcessDumpFile( Info.FullName, NewContext );
						}

						// Check to see if a new one has been created
						DiagnosticsInfo.Refresh();
						if( DiagnosticsInfo.Exists )
						{
							DiagnosticsFileName = DiagnosticsInfo.Name;	
						}
						break;

					default:
						break;
					}
				}

				// Check if the new context has processed data.
				if (!NewContext.HasProcessedData())
				{
					CrashReporterProcessServicer.WriteEvent(string.Format("PROC-{0} ", ProcessorIndex) + "% Warning no callstack or error msg : BuiltFromCL=" + string.Format("{0,7}", NewContext.PrimaryCrashProperties.EngineVersion) + " Path=" + NewContext.CrashDirectory);
					NewContext.PrimaryCrashProperties.ProcessorFailedMessage = "No callstack or error message. Diagnostics missing or failed.";
				}

				Stopwatch WaitSW = Stopwatch.StartNew();

				// Wait for previous task, should not really happen.
				int AddReportTaskSlot = WaitForFreeAddReportTask();
				CrashReporterProcessServicer.WriteEvent(string.Format("PROC-{0} ", ProcessorIndex) + string.Format("Starting AddReportTask running on slot {0} of {1} ({2} active)", AddReportTaskSlot, Config.Default.AddReportsPerProcessor, GetActiveAddReportTasks()));
				double WaitTime = WaitSW.Elapsed.TotalSeconds;

				//bool bAdded = AddReport(DirInfo, NewContext, LogFileName, DumpFileName, VideoFileName );
					
				// Save/update crash context to the file.
				NewContext.ToFile();
				AddReportTasks[AddReportTaskSlot] = Task.Factory.StartNew(() =>
				{
					bool bAdded = AddReport( DirInfo, NewContext, LogFileName, DumpFileName, VideoFileName );
					FinalizeReport( bAdded, DirInfo, NewContext );
				} );

				return WaitTime;

			}
			catch( Exception Ex )
			{
				CrashReporterProcessServicer.WriteException(string.Format("PROC-{0} ", ProcessorIndex) + "ProcessReport: " + NewContext.CrashDirectory + "\n\n: " + Ex.ToString());
			}

			return 0.0;
		}
		/// <summary>
		/// Create an Xml payload representing a new crash.
		/// </summary>
		/// <param name="DirInfo">The DirectoryInfo of the report folder.</param>
		/// <param name="NewContext">The generic crash context.</param>
		/// <param name="bHasVideoFile">Whether the report contains a video file.</param>
		/// <param name="bHasLog">Whether the report contains a log file.</param>
		/// <param name="bHasMinidump">Whether the report contains a minidump.</param>
		/// <returns>A string of Xml payload representing the newly found crash report.</returns>
		private string CreateCrash( DirectoryInfo DirInfo, FGenericCrashContext NewContext, bool bHasVideoFile, bool bHasLog, bool bHasMinidump )
		{
			string XmlPayload = "";
			try
			{
				FEngineVersion EngineVersion = new FEngineVersion( NewContext.PrimaryCrashProperties.EngineVersion ); 

				// Create a new crash description for uploading
				var NewCrash = new CrashDescription();

				NewCrash.CrashType = NewContext.PrimaryCrashProperties.GetCrashType();
				NewCrash.BranchName = EngineVersion.GetCleanedBranch();
				NewCrash.GameName = NewContext.PrimaryCrashProperties.GameName;
				NewCrash.Platform = NewContext.PrimaryCrashProperties.PlatformFullName;
				NewCrash.EngineMode = NewContext.PrimaryCrashProperties.EngineMode;
				NewCrash.EngineVersion = EngineVersion.VersionNumber;
			    NewCrash.BuildVersion = NewContext.PrimaryCrashProperties.BuildVersion;

				NewCrash.CommandLine = NewContext.PrimaryCrashProperties.CommandLine;
				NewCrash.BaseDir = NewContext.PrimaryCrashProperties.BaseDir;
			    NewCrash.bProcessorFailed = !string.IsNullOrWhiteSpace(NewContext.PrimaryCrashProperties.ProcessorFailedMessage);
				NewCrash.Language = NewContext.PrimaryCrashProperties.AppDefaultLocale;

// 				// Create a locate and get the system language.
// 				int SystemLanguageCode = 0;
// 				int.TryParse( ReportData.SystemLanguage, out SystemLanguageCode );
// 				try
// 				{
// 					if( SystemLanguageCode > 0 )
// 					{
// 						CultureInfo SystemLanguageCI = new CultureInfo( SystemLanguageCode );
// 						NewCrash.SystemLanguage = SystemLanguageCI.Name;
// 					}
// 				}
// 				catch( System.Exception )
// 				{
// 					// Default to en-US
// 					NewCrash.SystemLanguage = "en-US";
// 				}

				NewCrash.MachineGuid = NewContext.PrimaryCrashProperties.MachineId; // Valid for all kind of builds, previously only for UE4 releases.
				NewCrash.UserName = NewContext.PrimaryCrashProperties.UserName; // Only valid for non-UE4 releases.
				NewCrash.EpicAccountId = NewContext.PrimaryCrashProperties.EpicAccountId; // Only valid for UE4 releases.
				NewCrash.CallStack = NewContext.PrimaryCrashProperties.GetCallstack();
				NewCrash.SourceContext = NewContext.PrimaryCrashProperties.GetSourceContext();
				NewCrash.ErrorMessage = NewContext.PrimaryCrashProperties.GetErrorMessage();
				NewCrash.UserDescription = NewContext.PrimaryCrashProperties.GetUserDescription();
				NewCrash.UserActivityHint = NewContext.PrimaryCrashProperties.UserActivityHint;
				NewCrash.CrashGUID = NewContext.PrimaryCrashProperties.CrashGUID;

				// Iterate through all files and find a file with the earliest date.
				DateTime TimeOfCrash = DateTime.UtcNow;
				foreach( var File in DirInfo.GetFiles() )
				{
					if( File.CreationTimeUtc < TimeOfCrash )
					{
						TimeOfCrash = File.CreationTimeUtc;
					}
				}

				//NewCrash.TimeofCrash = NewContext.PrimaryCrashProperties.TimeofCrash;
				NewCrash.TimeofCrash = TimeOfCrash;
				
				NewCrash.bHasMiniDump = bHasMinidump;
				NewCrash.bHasLog = bHasLog;
				NewCrash.bHasVideo = bHasVideoFile;
				NewCrash.BuiltFromCL = (int)EngineVersion.Changelist;
				NewCrash.bAllowToBeContacted = NewContext.PrimaryCrashProperties.bAllowToBeContacted;

				// Ignore any callstack that is shorter than expected, usually the callstack is invalid.
				if( NewCrash.CallStack.Length <= CrashReporterConstants.MinCallstackDepth )
				{
					CrashReporterProcessServicer.WriteEvent(string.Format("PROC-{0} ", ProcessorIndex) + "! BadStack: BuiltFromCL=" + string.Format( "{0,7}", NewContext.PrimaryCrashProperties.EngineVersion ) + " Path=" + NewContext.CrashDirectory );
					NewContext.PrimaryCrashProperties.ProcessorFailedMessage = string.Format("Callstack was too small. {0} lines (minimum {1})", NewCrash.CallStack.Length, CrashReporterConstants.MinCallstackDepth);
                    NewContext.ToFile();
                }
				
				XmlPayload = XmlHandler.ToXmlString<CrashDescription>( NewCrash );
			}
			catch (Exception Ex)
			{
				CrashReporterProcessServicer.WriteException(string.Format("PROC-{0} ", ProcessorIndex) + "CreateCrash: " + Ex.ToString());
			}

			return XmlPayload;
		}