diff --git a/src/LogExpert.Core/Classes/Bookmark/BookmarkDataProvider.cs b/src/LogExpert.Core/Classes/Bookmark/BookmarkDataProvider.cs index 16656ffd..0a1e7963 100644 --- a/src/LogExpert.Core/Classes/Bookmark/BookmarkDataProvider.cs +++ b/src/LogExpert.Core/Classes/Bookmark/BookmarkDataProvider.cs @@ -13,6 +13,8 @@ public class BookmarkDataProvider : IBookmarkData private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); + private readonly Lock _bookmarkListLock = new(); + #endregion #region cTor @@ -49,7 +51,10 @@ public BookmarkDataProvider (SortedList bookmarkList) public void SetBookmarks (SortedList bookmarkList) { - BookmarkList = bookmarkList; + lock (_bookmarkListLock) + { + BookmarkList = bookmarkList; + } } public void ToggleBookmark (int lineNum) @@ -66,17 +71,26 @@ public void ToggleBookmark (int lineNum) public bool IsBookmarkAtLine (int lineNum) { - return BookmarkList.ContainsKey(lineNum); + lock (_bookmarkListLock) + { + return BookmarkList.ContainsKey(lineNum); + } } public int GetBookmarkIndexForLine (int lineNum) { - return BookmarkList.IndexOfKey(lineNum); + lock (_bookmarkListLock) + { + return BookmarkList.IndexOfKey(lineNum); + } } public Entities.Bookmark GetBookmarkForLine (int lineNum) { - return BookmarkList[lineNum]; + lock (_bookmarkListLock) + { + return BookmarkList[lineNum]; + } } #endregion @@ -116,6 +130,7 @@ public int FindPrevBookmarkIndex (int lineNum) public int FindNextBookmarkIndex (int lineNum) { + var values = BookmarkList.Values; for (var i = 0; i < BookmarkList.Count; ++i) { @@ -130,7 +145,11 @@ public int FindNextBookmarkIndex (int lineNum) public void RemoveBookmarkForLine (int lineNum) { - _ = BookmarkList.Remove(lineNum); + lock (_bookmarkListLock) + { + _ = BookmarkList.Remove(lineNum); + } + OnBookmarkRemoved(); } @@ -138,11 +157,13 @@ public void RemoveBookmarkForLine (int lineNum) public void RemoveBookmarksForLines (IEnumerable lineNumList) { ArgumentNullException.ThrowIfNull(lineNumList, nameof(lineNumList)); - - foreach (var lineNum in lineNumList) + lock (_bookmarkListLock) { - _ = BookmarkList.Remove(lineNum); + foreach (var lineNum in lineNumList) + { + _ = BookmarkList.Remove(lineNum); + } } OnBookmarkRemoved(); @@ -152,20 +173,31 @@ public void RemoveBookmarksForLines (IEnumerable lineNumList) public void AddBookmark (Entities.Bookmark bookmark) { ArgumentNullException.ThrowIfNull(bookmark, nameof(bookmark)); + lock (_bookmarkListLock) + { + BookmarkList.Add(bookmark.LineNum, bookmark); + } - BookmarkList.Add(bookmark.LineNum, bookmark); OnBookmarkAdded(); } public void ClearAllBookmarks () { +#if DEBUG _logger.Debug(CultureInfo.InvariantCulture, "Removing all bookmarks"); - BookmarkList.Clear(); +#endif + lock (_bookmarkListLock) + { + BookmarkList.Clear(); + } + OnAllBookmarksRemoved(); } #endregion + #region Event invokers + protected void OnBookmarkAdded () { BookmarkAdded?.Invoke(this, EventArgs.Empty); @@ -180,4 +212,7 @@ protected void OnAllBookmarksRemoved () { AllBookmarksRemoved?.Invoke(this, EventArgs.Empty); } + + #endregion + } \ No newline at end of file diff --git a/src/LogExpert.Core/Classes/Filter/FilterParams.cs b/src/LogExpert.Core/Classes/Filter/FilterParams.cs index 5e560fab..562b0fe3 100644 --- a/src/LogExpert.Core/Classes/Filter/FilterParams.cs +++ b/src/LogExpert.Core/Classes/Filter/FilterParams.cs @@ -86,11 +86,11 @@ public class FilterParams : ICloneable ///Returns RangeSearchText.ToUpperInvariant [JsonIgnore] - internal string NormalizedRangeSearchText => RangeSearchText.ToUpperInvariant(); + internal string NormalizedRangeSearchText => RangeSearchText?.ToUpperInvariant(); ///Returns SearchText.ToUpperInvariant [JsonIgnore] - internal string NormalizedSearchText => SearchText.ToUpperInvariant(); + internal string NormalizedSearchText => SearchText?.ToUpperInvariant(); [JsonIgnore] [field: NonSerialized] diff --git a/src/LogExpert.Core/Entities/LogEventData.cs b/src/LogExpert.Core/Entities/LogEventData.cs index 70b368b5..1dc035ae 100644 --- a/src/LogExpert.Core/Entities/LogEventData.cs +++ b/src/LogExpert.Core/Entities/LogEventData.cs @@ -1,6 +1,6 @@ -namespace LogExpert.Core.Entities; +namespace LogExpert.Core.Entities; -public class LogEventArgs : System.EventArgs +public class LogEventArgs : EventArgs { #region Fields diff --git a/src/LogExpert.Tests/HighlightBookmarkTriggerTests.cs b/src/LogExpert.Tests/HighlightBookmarkTriggerTests.cs new file mode 100644 index 00000000..a50730a9 --- /dev/null +++ b/src/LogExpert.Tests/HighlightBookmarkTriggerTests.cs @@ -0,0 +1,351 @@ +using LogExpert.Core.Classes.Bookmark; +using LogExpert.Core.Classes.Highlight; +using LogExpert.Core.Entities; + +using NUnit.Framework; + +namespace LogExpert.Tests; + +[TestFixture] +public class HighlightBookmarkTriggerTests +{ + #region GetHighlightActions Tests + + [Test] + public void GetHighlightActions_WhenIsSetBookmarkTrue_ReturnsSetBookmarkTrue () + { + // Arrange + var entry = new HighlightEntry + { + SearchText = "ERROR", + IsSetBookmark = true, + BookmarkComment = "Error found" + }; + IList matchingList = [entry]; + + // Act — GetHighlightActions is a private static method in LogWindow. + // We replicate its logic here to test the contract. + var (_, _, setBookmark, bookmarkComment) = ExtractHighlightActions(matchingList); + + // Assert + Assert.That(setBookmark, Is.True); + Assert.That(bookmarkComment, Is.EqualTo("Error found")); + } + + [Test] + public void GetHighlightActions_WhenIsSetBookmarkFalse_ReturnsSetBookmarkFalse () + { + // Arrange + var entry = new HighlightEntry + { + SearchText = "INFO", + IsSetBookmark = false + }; + IList matchingList = [entry]; + + // Act + var (_, _, setBookmark, _) = ExtractHighlightActions(matchingList); + + // Assert + Assert.That(setBookmark, Is.False); + } + + [Test] + public void GetHighlightActions_WhenMultipleEntriesWithBookmarks_ConcatenatesComments () + { + // Arrange + var entry1 = new HighlightEntry + { + SearchText = "ERROR", + IsSetBookmark = true, + BookmarkComment = "First" + }; + + var entry2 = new HighlightEntry + { + SearchText = "WARN", + IsSetBookmark = true, + BookmarkComment = "Second" + }; + + IList matchingList = [entry1, entry2]; + + // Act + var (_, _, setBookmark, bookmarkComment) = ExtractHighlightActions(matchingList); + + // Assert + Assert.That(setBookmark, Is.True); + Assert.That(bookmarkComment, Is.EqualTo("First\r\nSecond")); + } + + [Test] + public void GetHighlightActions_WhenEmptyList_ReturnsAllFalse () + { + // Arrange + IList matchingList = []; + + // Act + var (noLed, stopTail, setBookmark, bookmarkComment) = ExtractHighlightActions(matchingList); + + // Assert + Assert.That(noLed, Is.False); + Assert.That(stopTail, Is.False); + Assert.That(setBookmark, Is.False); + Assert.That(bookmarkComment, Is.Empty); + } + + [Test] + public void GetHighlightActions_WhenBookmarkCommentIsEmpty_ReturnsSetBookmarkTrueWithEmptyComment () + { + // Arrange + var entry = new HighlightEntry + { + SearchText = "ERROR", + IsSetBookmark = true, + BookmarkComment = string.Empty + }; + IList matchingList = [entry]; + + // Act + var (_, _, setBookmark, bookmarkComment) = ExtractHighlightActions(matchingList); + + // Assert + Assert.That(setBookmark, Is.True); + Assert.That(bookmarkComment, Is.Empty); + } + + [Test] + public void GetHighlightActions_WhenBookmarkCommentIsNull_ReturnsSetBookmarkTrueWithEmptyComment () + { + // Arrange + var entry = new HighlightEntry + { + SearchText = "ERROR", + IsSetBookmark = true, + BookmarkComment = null + }; + IList matchingList = [entry]; + + // Act + var (_, _, setBookmark, bookmarkComment) = ExtractHighlightActions(matchingList); + + // Assert + Assert.That(setBookmark, Is.True); + Assert.That(bookmarkComment, Is.Empty); + } + + /// + /// Replicates the logic from LogWindow.GetHighlightActions (private static). + /// This must stay in sync with the actual implementation. + /// If the implementation is refactored to be testable directly, remove this helper. + /// + private static (bool NoLed, bool StopTail, bool SetBookmark, string BookmarkComment) ExtractHighlightActions (IList matchingList) + { + var noLed = false; + var stopTail = false; + var setBookmark = false; + var bookmarkComment = string.Empty; + + foreach (var entry in matchingList) + { + if (entry.IsLedSwitch) + { + noLed = true; + } + + if (entry.IsSetBookmark) + { + setBookmark = true; + if (!string.IsNullOrEmpty(entry.BookmarkComment)) + { + bookmarkComment += entry.BookmarkComment + "\r\n"; + } + } + + if (entry.IsStopTail) + { + stopTail = true; + } + } + + bookmarkComment = bookmarkComment.TrimEnd(['\r', '\n']); + + return (noLed, stopTail, setBookmark, bookmarkComment); + } + + #endregion + + #region BookmarkDataProvider Tests + + [Test] + public void BookmarkDataProvider_AddBookmark_IsBookmarkAtLineReturnsTrue () + { + // Arrange + var provider = new BookmarkDataProvider(); + var bookmark = new Bookmark(42, "Test comment"); + + // Act + provider.AddBookmark(bookmark); + + // Assert + Assert.That(provider.IsBookmarkAtLine(42), Is.True); + } + + [Test] + public void BookmarkDataProvider_AddBookmark_GetBookmarkReturnsCorrectBookmark () + { + // Arrange + var provider = new BookmarkDataProvider(); + var bookmark = new Bookmark(42, "Test comment"); + + // Act + provider.AddBookmark(bookmark); + var result = provider.GetBookmarkForLine(42); + + // Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.LineNum, Is.EqualTo(42)); + Assert.That(result.Text, Is.EqualTo("Test comment")); + } + + [Test] + public void BookmarkDataProvider_RemoveBookmark_IsBookmarkAtLineReturnsFalse () + { + // Arrange + var provider = new BookmarkDataProvider(); + provider.AddBookmark(new Bookmark(42, "Test")); + + // Act + provider.RemoveBookmarkForLine(42); + + // Assert + Assert.That(provider.IsBookmarkAtLine(42), Is.False); + } + + [Test] + public void BookmarkDataProvider_AddBookmark_FiresBookmarkAddedEvent () + { + // Arrange + var provider = new BookmarkDataProvider(); + var eventFired = false; + provider.BookmarkAdded += (_, _) => eventFired = true; + + // Act + provider.AddBookmark(new Bookmark(42)); + + // Assert + Assert.That(eventFired, Is.True); + } + + #endregion + + #region HighlightEntry Serialization Tests + + [Test] + public void HighlightEntry_Clone_PreservesIsSetBookmark () + { + // Arrange + var entry = new HighlightEntry + { + SearchText = "ERROR", + IsSetBookmark = true, + BookmarkComment = "Critical error" + }; + + // Act + var clone = entry.Clone(); + + // Assert + Assert.That(((HighlightEntry)clone).IsSetBookmark, Is.True); + Assert.That(((HighlightEntry)clone).BookmarkComment, Is.EqualTo("Critical error")); + } + + [Test] + public void HighlightEntry_Clone_PreservesIsSetBookmarkWhenFalse () + { + // Arrange + var entry = new HighlightEntry + { + SearchText = "INFO", + IsSetBookmark = false, + BookmarkComment = string.Empty + }; + + // Act + var clone = entry.Clone(); + + // Assert + Assert.That(((HighlightEntry)clone).IsSetBookmark, Is.False); + } + + #endregion + + #region Closure Regression Tests + + /// + /// Demonstrates the closure-over-loop-variable bug pattern. + /// This test proves the bug exists when loop variables are captured directly. + /// If this test fails in the future, the C# language has changed loop variable capture semantics for `for` loops. + /// + [Test] + public void ClosureBug_ForLoopVariable_CapturedByReference_DemonstratesBug () + { + // Arrange + var capturedValues = new List(); + var tasks = new List(); + + // Act — simulate the buggy pattern + for (var i = 0; i < 5; i++) + { + // -- BUG PATTERN: capturing `i` directly + tasks.Add(Task.Run(() => + { + lock (capturedValues) + { + capturedValues.Add(i); + } + })); + } + + Task.WaitAll([.. tasks]); + + // Assert — at least one value should be wrong (likely all are 5) + // The key observation: NOT all values 0..4 are present + var hasAllExpected = capturedValues.Order().SequenceEqual([0, 1, 2, 3, 4]); + Assert.That(hasAllExpected, Is.False, + "If this fails, the closure-over-loop-variable issue no longer applies to `for` loops in this C# version."); + } + + /// + /// Demonstrates the correct pattern — capturing the loop variable in a local. + /// This is the pattern that must be applied in CheckFilterAndHighlight(). + /// + [Test] + public void ClosureFix_LocalCapture_AllValuesCorrect () + { + // Arrange + var capturedValues = new List(); + var tasks = new List(); + + // Act — correct pattern: capture in local variable + for (var i = 0; i < 5; i++) + { + var captured = i; // FIX: local capture + tasks.Add(Task.Run(() => + { + lock (capturedValues) + { + capturedValues.Add(captured); + } + })); + } + + Task.WaitAll([.. tasks]); + + // Assert — all values 0..4 must be present + capturedValues.Sort(); + Assert.That(capturedValues, Is.EquivalentTo([0, 1, 2, 3, 4])); + } + + #endregion +} \ No newline at end of file diff --git a/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs b/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs index e300fa26..5039c726 100644 --- a/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs +++ b/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs @@ -51,7 +51,6 @@ internal partial class LogWindow : DockContent, ILogPaintContextUI, ILogView, IL private readonly Image _advancedButtonImage; - private readonly Lock _bookmarkLock = new(); private readonly BookmarkDataProvider _bookmarkProvider = new(); private readonly IList _cancelHandlerList = []; @@ -70,7 +69,7 @@ internal partial class LogWindow : DockContent, ILogPaintContextUI, ILogView, IL private readonly EventWaitHandle _loadingFinishedEvent = new ManualResetEvent(false); - private readonly EventWaitHandle _logEventArgsEvent = new ManualResetEvent(false); + private readonly EventWaitHandle _logEventArgsEvent = new AutoResetEvent(false); private readonly List _logEventArgsList = []; private readonly Task _logEventHandlerTask; @@ -223,11 +222,9 @@ public LogWindow (ILogWindowCoordinator logWindowCoordinator, string fileName, b splitContainerLogWindow.Panel2Collapsed = true; advancedFilterSplitContainer.SplitterDistance = FILTER_ADVANCED_SPLITTER_DISTANCE; - _timeShiftSyncTask = new Task(SyncTimestampDisplayWorker, cts.Token); - _timeShiftSyncTask.Start(); + _timeShiftSyncTask = Task.Factory.StartNew(SyncTimestampDisplayWorker, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); - _logEventHandlerTask = new Task(LogEventWorker, cts.Token); - _logEventHandlerTask.Start(); + _logEventHandlerTask = Task.Factory.StartNew(LogEventWorker, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); //this.filterUpdateThread = new Thread(new ThreadStart(this.FilterUpdateWorker)); //this.filterUpdateThread.Start(); @@ -782,6 +779,7 @@ protected void OnCurrentHighlightListChanged () CurrentHighlightGroupChanged?.Invoke(this, new CurrentHighlightGroupChangedEventArgs(this, _currentHighlightGroup)); } + //TODO Double Check why the bookmark Providers have the Event and the LogWindow, and if it still necessary protected void OnBookmarkAdded () { BookmarkAdded?.Invoke(this, EventArgs.Empty); @@ -2930,7 +2928,6 @@ private void LogEventWorker () //_logger.Info($"{_logEventArgsList.Count} events in queue"); if (_logEventArgsList.Count == 0) { - _ = _logEventArgsEvent.Reset(); break; } @@ -2961,7 +2958,7 @@ private void LogEventWorker () { try { - _ = Invoke(UpdateGrid, [e]); + _ = BeginInvoke(UpdateGrid, [e]); CheckFilterAndHighlight(e); } catch (ObjectDisposedException) @@ -3127,7 +3124,9 @@ private void CheckFilterAndHighlight (LogEventArgs e) var (suppressLed, stopTail, setBookmark, bookmarkComment) = GetHighlightActions(matchingList); if (setBookmark) { - _ = Task.Run(() => SetBookmarkFromTrigger(i, bookmarkComment)); + var capturedLineNum = i; + var capturedComment = bookmarkComment; + _ = BeginInvoke(() => SetBookmarkFromTrigger(capturedLineNum, capturedComment)); } if (stopTail && _guiStateArgs.FollowTail) @@ -3137,7 +3136,8 @@ private void CheckFilterAndHighlight (LogEventArgs e) if (firstStopTail && wasFollow) { //_ = Invoke(new SelectLineFx(SelectAndEnsureVisible), [i, false]); - _ = Task.Run(() => SelectAndEnsureVisible(i, false)); + var capturedLineNum = i; + _ = BeginInvoke(() => SelectAndEnsureVisible(capturedLineNum, false)); firstStopTail = false; } } @@ -3175,8 +3175,9 @@ private void CheckFilterAndHighlight (LogEventArgs e) var (suppressLed, stopTail, setBookmark, bookmarkComment) = GetHighlightActions(matchingList); if (setBookmark) { - //SetBookmarkFx fx = SetBookmarkFromTrigger; - _ = Task.Run(() => SetBookmarkFromTrigger(i, bookmarkComment)); + var capturedLineNum = i; + var capturedComment = bookmarkComment; + _ = BeginInvoke(() => SetBookmarkFromTrigger(capturedLineNum, capturedComment)); //_ = fx.BeginInvoke(i, bookmarkComment, null, null); } @@ -3187,7 +3188,8 @@ private void CheckFilterAndHighlight (LogEventArgs e) if (firstStopTail && wasFollow) { //_ = Invoke(new SelectLineFx(SelectAndEnsureVisible), [i, false]); - _ = Task.Run(() => SelectAndEnsureVisible(i, false)); + var capturedLineNum = i; + _ = BeginInvoke(() => SelectAndEnsureVisible(capturedLineNum, false)); firstStopTail = false; } } @@ -7005,34 +7007,34 @@ public void ToggleBookmark (int lineNum) public void SetBookmarkFromTrigger (int lineNum, string comment) { - lock (_bookmarkLock) - { - var line = _logFileReader.GetLogLineMemory(lineNum); - - if (line == null) - { - return; - } + var line = _logFileReader.GetLogLineMemory(lineNum); - var paramParser = new ParamParser(comment); + if (line == null) + { +#if DEBUG + _logger.Warn($"SetBookmarkFromTrigger: line {lineNum} returned null, bookmark not set"); +#endif + return; + } - try - { - comment = paramParser.ReplaceParams(line, lineNum, FileName); - } - catch (ArgumentException) - { - // occurs on invalid regex - } + var paramParser = new ParamParser(comment); - if (_bookmarkProvider.IsBookmarkAtLine(lineNum)) - { - _bookmarkProvider.RemoveBookmarkForLine(lineNum); - } + try + { + comment = paramParser.ReplaceParams(line, lineNum, FileName); + } + catch (ArgumentException) + { + // occurs on invalid regex + } - _bookmarkProvider.AddBookmark(new Bookmark(lineNum, comment)); - OnBookmarkAdded(); + if (_bookmarkProvider.IsBookmarkAtLine(lineNum)) + { + _bookmarkProvider.RemoveBookmarkForLine(lineNum); } + + _bookmarkProvider.AddBookmark(new Bookmark(lineNum, comment)); + OnBookmarkAdded(); } public void JumpNextBookmark () diff --git a/src/PluginRegistry/PluginHashGenerator.Generated.cs b/src/PluginRegistry/PluginHashGenerator.Generated.cs index 9d06d000..034207e3 100644 --- a/src/PluginRegistry/PluginHashGenerator.Generated.cs +++ b/src/PluginRegistry/PluginHashGenerator.Generated.cs @@ -10,7 +10,7 @@ public static partial class PluginValidator { /// /// Gets pre-calculated SHA256 hashes for built-in plugins. - /// Generated: 2026-04-08 07:36:39 UTC + /// Generated: 2026-04-08 11:38:39 UTC /// Configuration: Release /// Plugin count: 22 /// @@ -18,28 +18,28 @@ public static Dictionary GetBuiltInPluginHashes() { return new Dictionary(StringComparer.OrdinalIgnoreCase) { - ["AutoColumnizer.dll"] = "16B4911C5434A32CE56FC6E2FD736BCE09A60763AAA89516D5830DCA57F2FC98", + ["AutoColumnizer.dll"] = "71ADBC14647A3518D5BCC9B7C457E245ED9BC09361DF86E35F720810C287EB4E", ["BouncyCastle.Cryptography.dll"] = "E5EEAF6D263C493619982FD3638E6135077311D08C961E1FE128F9107D29EBC6", ["BouncyCastle.Cryptography.dll (x86)"] = "E5EEAF6D263C493619982FD3638E6135077311D08C961E1FE128F9107D29EBC6", - ["CsvColumnizer.dll"] = "09A5788A8CF879D167386B7B0281EAE7872CC3EB5F8580D203D7C8170FB2E557", - ["CsvColumnizer.dll (x86)"] = "09A5788A8CF879D167386B7B0281EAE7872CC3EB5F8580D203D7C8170FB2E557", - ["DefaultPlugins.dll"] = "11C939FF576411744B4529363F39BFD4E9EBB89E5578D142D3B661E4A3027126", - ["FlashIconHighlighter.dll"] = "C395463B2A0B9585D0195EEAD3AD9573AA1DADC784B00813239CA30BEA72E0AA", - ["GlassfishColumnizer.dll"] = "796DE5895F8CA06579F9026F16F66229C8B67F33681DABCC51D07BB2C13865B0", - ["JsonColumnizer.dll"] = "903342AC2A712C59932ECF3C74E27B88C7DC95337330FD733424042E10FA9C9C", - ["JsonCompactColumnizer.dll"] = "C5E19A193D76104A005483065E1649C15CA2D3C495A9BB465D95341006ECFE2A", - ["Log4jXmlColumnizer.dll"] = "544A78E1C538F31310A48FD0F894D4A7A602C46BA04FFCB74DD1035A45AC91FF", - ["LogExpert.Core.dll"] = "77BF77CEBCCE5C3DBFCCD9CE3D6D175436532D78AE2EB6B92B10602792FAE117", - ["LogExpert.Resources.dll"] = "869425BD30DA40E85F367C3D082F62C78F20B7DBC81F0960BE45884BFBFBA575", + ["CsvColumnizer.dll"] = "C8222B75CA9624DBF4AB4E61E267B1A77D89F8DF060936E089B028CDEE640BCB", + ["CsvColumnizer.dll (x86)"] = "C8222B75CA9624DBF4AB4E61E267B1A77D89F8DF060936E089B028CDEE640BCB", + ["DefaultPlugins.dll"] = "B6522E225406331F33F85AA632E137EDC09A979ED616C075783EB08E346E236E", + ["FlashIconHighlighter.dll"] = "895F1716EBAC443B0960D39C97041ABD19B93F81387CF3CDDA831E3DB3FD6504", + ["GlassfishColumnizer.dll"] = "E7B51257921307710D6ECDE215F55E7FBB62EE509CA8C5573D111D7576ECB5BE", + ["JsonColumnizer.dll"] = "E64E8482258A9569EB5C2143CAD23711A192434A78F36B83743885EDF0BA44F1", + ["JsonCompactColumnizer.dll"] = "4C5019A770C94A84269C373C577DD5C399CF7A9A9A2F3D840E5C267D67B96E19", + ["Log4jXmlColumnizer.dll"] = "DF8E5AF3C23E4475902BD14C459E744A0EB14BFFF65CF423B8F3B81C6D636F92", + ["LogExpert.Core.dll"] = "F6E015EDA26C27BB8C5571527525C3A63DB7C3B90B73DC2B28803455AFAF7899", + ["LogExpert.Resources.dll"] = "C6CC3738AB9C5FC016B524E08B80CB31A8783550A0DDB864BDE97A93EAAEE9EE", ["Microsoft.Extensions.DependencyInjection.Abstractions.dll"] = "67FA4325000DB017DC0C35829B416F024F042D24EFB868BCF17A895EE6500A93", ["Microsoft.Extensions.DependencyInjection.Abstractions.dll (x86)"] = "67FA4325000DB017DC0C35829B416F024F042D24EFB868BCF17A895EE6500A93", ["Microsoft.Extensions.Logging.Abstractions.dll"] = "BB853130F5AFAF335BE7858D661F8212EC653835100F5A4E3AA2C66A4D4F685D", ["Microsoft.Extensions.Logging.Abstractions.dll (x86)"] = "BB853130F5AFAF335BE7858D661F8212EC653835100F5A4E3AA2C66A4D4F685D", - ["RegexColumnizer.dll"] = "E93D37F9344CECA55EE40133B38801BFBC5D4B0AE0DDF10C04EEAD70CAE08CC0", - ["SftpFileSystem.dll"] = "04CAC2FCD43803C8EBF090A41D458674BDE5AB98CAC2452D29A2CDF58F6C29CC", - ["SftpFileSystem.dll (x86)"] = "2822F059492BCE7902CAF521A034624B1DEA615AE935A1D082B591EE8179245B", - ["SftpFileSystem.Resources.dll"] = "166515F144CD78ACC8E5C3827AAAF24959F9AD7786917791FB71398B03014C32", - ["SftpFileSystem.Resources.dll (x86)"] = "166515F144CD78ACC8E5C3827AAAF24959F9AD7786917791FB71398B03014C32", + ["RegexColumnizer.dll"] = "5FCDACB87036DACC72DFAF7F61D44087F21C835E4AE1EAFED3E072D3F45E6F9E", + ["SftpFileSystem.dll"] = "90923B8231C88526EA10BAB744360B1B0DCBD9C7E09DF332C4C52EC79D594468", + ["SftpFileSystem.dll (x86)"] = "BFACC69BF8CF3CA6255C2D1F7DEEEA7D79FE6804121A9E6FFE2B345B8772BF91", + ["SftpFileSystem.Resources.dll"] = "148A73361F30CCC5B0CBF46D3B38D83FE0F21F3D9B43D567AE6D29636D49A801", + ["SftpFileSystem.Resources.dll (x86)"] = "148A73361F30CCC5B0CBF46D3B38D83FE0F21F3D9B43D567AE6D29636D49A801", }; }