public void DayRolloverTest()
		{
			if(DateTime.Now.AddSeconds(5).Date > DateTime.Now.Date)
				Thread.Sleep(5000);
			const string line = "D 23:59:59.9999999 GameState.DebugPrintPower() -     tag=ZONE value=PLAY";
			var lineItem = new LogLineItem("Power", line);
			Assert.AreEqual(lineItem.Time.Date, DateTime.Now.Date.AddDays(-1));
		}
 private void ReadLogFile()
 {
     _running = true;
     FindInitialOffset();
     while (!_stop)
     {
         lock (_sync)
         {
             if (_collected)
             {
                 _lines.Clear();
                 _collected = false;
             }
             var fileInfo = new FileInfo(_filePath);
             if (fileInfo.Exists)
             {
                 if (!_logFileExists)
                 {
                     _logFileExists = true;
                     Log.Info($"Found {Info.Name}.log.");
                 }
                 using (var fs = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                 {
                     fs.Seek(_offset, SeekOrigin.Begin);
                     if (fs.Length == _offset)
                     {
                         Thread.Sleep(Config.Instance.UpdateDelay);
                         continue;
                     }
                     using (var sr = new StreamReader(fs))
                     {
                         string line;
                         while (!sr.EndOfStream && (line = sr.ReadLine()) != null)
                         {
                             if (!line.StartsWith("D ") || (!sr.EndOfStream && sr.Peek() != 'D'))
                             {
                                 break;
                             }
                             if (!Info.HasFilters || (Info.StartsWithFilters?.Any(x => line.Substring(19).StartsWith(x)) ?? false) ||
                                 (Info.ContainsFilters?.Any(x => line.Substring(19).Contains(x)) ?? false))
                             {
                                 var logLine = new LogLineItem(Info.Name, line);
                                 if (logLine.Time >= _startingPoint)
                                 {
                                     _lines.Add(logLine);
                                 }
                             }
                             _offset += Encoding.UTF8.GetByteCount(line + Environment.NewLine);
                         }
                     }
                 }
             }
         }
         Thread.Sleep(Config.Instance.UpdateDelay);
     }
     _running = false;
 }
 private void ReadLogFile()
 {
     _running = true;
     FindInitialOffset();
     while (!_stop)
     {
         var fileInfo = new FileInfo(_filePath);
         if (fileInfo.Exists)
         {
             if (!_logFileExists)
             {
                 _logFileExists = true;
                 Log.Info($"Found {Info.Name}.log.");
             }
             using (var fs = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
             {
                 fs.Seek(_offset, SeekOrigin.Begin);
                 if (fs.Length == _offset)
                 {
                     Thread.Sleep(LogReaderManager.UpdateDelay);
                     continue;
                 }
                 using (var sr = new StreamReader(fs))
                 {
                     string line;
                     while (!sr.EndOfStream && (line = sr.ReadLine()) != null)
                     {
                         if (line.StartsWith("D "))
                         {
                             var next = sr.Peek();
                             if (!sr.EndOfStream && !(next == 'D' || next == 'W'))
                             {
                                 break;
                             }
                             var logLine = new LogLineItem(Info.Name, line);
                             if ((!Info.HasFilters || (Info.StartsWithFilters?.Any(x => logLine.LineContent.StartsWith(x)) ?? false) ||
                                  (Info.ContainsFilters?.Any(x => logLine.LineContent.Contains(x)) ?? false)) &&
                                 logLine.Time >= _startingPoint)
                             {
                                 _lines.Enqueue(logLine);
                             }
                         }
                         else
                         {
                             Log.Warn("Ignored line: " + line);
                         }
                         _offset += Encoding.UTF8.GetByteCount(line + Environment.NewLine);
                     }
                 }
             }
         }
         Thread.Sleep(LogReaderManager.UpdateDelay);
     }
     _running = false;
 }
        private void FindInitialOffset()
        {
            var fileInfo = new FileInfo(_filePath);

            if (fileInfo.Exists)
            {
                using (var fs = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    using (var sr = new StreamReader(fs, Encoding.ASCII))
                    {
                        var offset = 0;
                        while (offset < fs.Length)
                        {
                            var sizeDiff = 4096 - Math.Min(fs.Length - offset, 4096);
                            offset += 4096;
                            var buffer = new char[4096];
                            fs.Seek(Math.Max(fs.Length - offset, 0), SeekOrigin.Begin);
                            sr.ReadBlock(buffer, 0, 4096);
                            var skip = 0;
                            for (var i = 0; i < 4096; i++)
                            {
                                skip++;
                                if (buffer[i] == '\n')
                                {
                                    break;
                                }
                            }
                            offset -= skip;
                            var lines = (new string(buffer.Skip(skip).ToArray())).Split(new [] { Environment.NewLine }, StringSplitOptions.None).ToArray();
                            for (int i = lines.Length - 1; i > 0; i--)
                            {
                                if (string.IsNullOrWhiteSpace(lines[i].Trim('\0')))
                                {
                                    continue;
                                }
                                var logLine = new LogLineItem(_info.Name, lines[i], fileInfo.LastWriteTime);
                                if (logLine.Time < _startingPoint)
                                {
                                    var negativeOffset = lines.Take(i + 1).Sum(x => Encoding.UTF8.GetByteCount(x + Environment.NewLine));
                                    _offset = Math.Max(fs.Length - offset + negativeOffset + sizeDiff, 0);
                                    return;
                                }
                            }
                        }
                    }
                }
            }
            _offset = 0;
        }
		private void FindInitialOffset()
		{
			var fileInfo = new FileInfo(_filePath);
			if(fileInfo.Exists)
			{
				using(var fs = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
				using(var sr = new StreamReader(fs, Encoding.ASCII))
				{
					var offset = 0;
					while(offset < fs.Length)
					{
						var sizeDiff = 4096 - Math.Min(fs.Length - offset, 4096);
						offset += 4096;
						var buffer = new char[4096];
						fs.Seek(Math.Max(fs.Length - offset, 0), SeekOrigin.Begin);
						sr.ReadBlock(buffer, 0, 4096);
						var skip = 0;
						for(var i = 0; i < 4096; i++)
						{
							skip++;
							if(buffer[i] == '\n')
								break;
						}
						offset -= skip;
						var lines = (new string(buffer.Skip(skip).ToArray())).Split(new[] {Environment.NewLine}, StringSplitOptions.None).ToArray();
						for(int i = lines.Length - 1; i > 0; i--)
						{
							if(string.IsNullOrWhiteSpace(lines[i].Trim('\0')))
								continue;
							var logLine = new LogLineItem(Info.Name, lines[i]);
							if(logLine.Time < _startingPoint)
							{
								var negativeOffset = lines.Take(i + 1).Sum(x => Encoding.UTF8.GetByteCount(x + Environment.NewLine));
								_offset = Math.Max(fs.Length - offset + negativeOffset + sizeDiff, 0);
								return;
							}
						}
					}
				}
			}
			_offset = 0;
		}
		private void ReadLogFile()
		{
			_running = true;
			FindInitialOffset();
			while(!_stop)
			{
				lock(_sync)
				{
					if(_collected)
					{
						_lines.Clear();
						_collected = false;
					}
					var fileInfo = new FileInfo(_filePath);
					if(fileInfo.Exists)
					{
						if(!_logFileExists)
						{
							_logFileExists = true;
							Log.Info($"Found {Info.Name}.log.");
						}
						using(var fs = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
						{
							fs.Seek(_offset, SeekOrigin.Begin);
							if(fs.Length == _offset)
							{
								Thread.Sleep(LogReaderManager.UpdateDelay);
								continue;
							}
							using(var sr = new StreamReader(fs))
							{
								string line;
								while(!sr.EndOfStream && (line = sr.ReadLine()) != null)
								{
									if(!line.StartsWith("D ") || (!sr.EndOfStream && sr.Peek() != 'D'))
										break;
									if(!Info.HasFilters || (Info.StartsWithFilters?.Any(x => line.Substring(19).StartsWith(x)) ?? false)
									   || (Info.ContainsFilters?.Any(x => line.Substring(19).Contains(x)) ?? false))
									{
										var logLine = new LogLineItem(Info.Name, line);
										if(logLine.Time >= _startingPoint)
											_lines.Add(logLine);
									}
									_offset += Encoding.UTF8.GetByteCount(line + Environment.NewLine);
								}
							}
						}
					}
				}
				Thread.Sleep(LogReaderManager.UpdateDelay);
			}
			_running = false;
		}
		public void LineContentTest()
		{
			const string line = "D 00:06:10.0010000 GameState.DebugPrintPower() -     tag=ZONE value=PLAY";
			var lineItem = new LogLineItem("Power", line);
			Assert.AreEqual("D " + lineItem.Time.ToString("HH:mm:ss.fffffff") + " " + lineItem.LineContent, line);
		}
		private void ReadLogFile()
		{
			_running = true;
			while(!_stop)
			{
				lock(_sync)
				{
					if(_collected)
					{
						_lines.Clear();
						_collected = false;
					}
					var fileInfo = new FileInfo(_filePath);
					if(fileInfo.Exists)
					{
						using (var fs = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
						{
							fs.Seek(_offset, SeekOrigin.Begin);
							if(fs.Length == _offset)
							{
								Thread.Sleep(Config.Instance.UpdateDelay);
								continue;
							}
							using (var sr = new StreamReader(fs))
							{
								string line;
								while(!sr.EndOfStream && (line = sr.ReadLine()) != null)
								{
									if(!line.StartsWith("D ") || (!sr.EndOfStream && sr.Peek() != 'D'))
										break;
									if(!_info.HasFilters || _info.StartsWithFilters.Any(x => line.Substring(19).StartsWith(x))
									   || _info.ContainsFilters.Any(x => line.Substring(19).Contains(x)))
									{
										var logLine = new LogLineItem(_info.Name, line, fileInfo.LastWriteTime);
										if(logLine.Time >= _startingPoint)
											_lines.Add(logLine);
									}
									_offset += line.Length + Environment.NewLine.Length;
								}
							}
						}
					}
				}
				Thread.Sleep(Config.Instance.UpdateDelay);
			}
			_running = false;
		}
		private void ReadLogFile()
		{
			_running = true;
			FindInitialOffset();
			while(!_stop)
			{
				var fileInfo = new FileInfo(_filePath);
				if(fileInfo.Exists)
				{
					if(!_logFileExists)
					{
						_logFileExists = true;
						Log.Info($"Found {Info.Name}.log.");
					}
					using(var fs = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
					{
						fs.Seek(_offset, SeekOrigin.Begin);
						if(fs.Length == _offset)
						{
							Thread.Sleep(LogReaderManager.UpdateDelay);
							continue;
						}
						using(var sr = new StreamReader(fs))
						{
							string line;
							while(!sr.EndOfStream && (line = sr.ReadLine()) != null)
							{
								if(line.StartsWith("D "))
								{
									var next = sr.Peek();
									if(!sr.EndOfStream && !(next == 'D' || next == 'W'))
										break;
									var logLine = new LogLineItem(Info.Name, line);
									if((!Info.HasFilters || (Info.StartsWithFilters?.Any(x => logLine.LineContent.StartsWith(x)) ?? false)
										|| (Info.ContainsFilters?.Any(x => logLine.LineContent.Contains(x)) ?? false))
										&& logLine.Time >= _startingPoint)
										_lines.Enqueue(logLine);
								}
								else
									Log.Warn("Ignored line: " + line);
								_offset += Encoding.UTF8.GetByteCount(line + Environment.NewLine);
							}
						}
					}
				}
				Thread.Sleep(LogReaderManager.UpdateDelay);
			}
			_running = false;
		}