diff --git a/src/MaksIT.Core.Tests/LoggerHelper.cs b/src/MaksIT.Core.Tests/LoggerHelper.cs
new file mode 100644
index 0000000..ab0991e
--- /dev/null
+++ b/src/MaksIT.Core.Tests/LoggerHelper.cs
@@ -0,0 +1,42 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+using MaksIT.Core.Logging;
+
+namespace MaksIT.Core.Tests;
+
+/// 
+/// Provides helper methods for creating loggers in tests.
+/// 
+public static class LoggerHelper
+{
+    /// 
+    /// Creates a console logger for testing purposes.
+    /// 
+    /// An instance of  configured for console logging.
+    public static ILogger CreateConsoleLogger()
+    {
+        var serviceCollection = new ServiceCollection();
+
+        // Use the reusable TestHostEnvironment for testing
+        serviceCollection.AddSingleton(sp =>
+            new TestHostEnvironment
+            {
+                EnvironmentName = Environments.Development,
+                ApplicationName = "TestApp",
+                ContentRootPath = Directory.GetCurrentDirectory()
+            });
+
+        serviceCollection.AddLogging(builder =>
+        {
+            var env = serviceCollection.BuildServiceProvider().GetRequiredService();
+            builder.ClearProviders();
+            builder.AddConsole(env);
+        });
+
+        var provider = serviceCollection.BuildServiceProvider();
+        var factory = provider.GetRequiredService();
+        return factory.CreateLogger("TestLogger");
+    }
+}
\ No newline at end of file
diff --git a/src/MaksIT.Core.Tests/MaksIT.Core.Tests.csproj b/src/MaksIT.Core.Tests/MaksIT.Core.Tests.csproj
index 77f9d3c..24d3a2f 100644
--- a/src/MaksIT.Core.Tests/MaksIT.Core.Tests.csproj
+++ b/src/MaksIT.Core.Tests/MaksIT.Core.Tests.csproj
@@ -14,9 +14,10 @@
       all
       runtime; build; native; contentfiles; analyzers; buildtransitive
     
-    
+    
+    
     
-    
+    
       all
       runtime; build; native; contentfiles; analyzers; buildtransitive
     
@@ -30,4 +31,8 @@
     
   
 
+  
+    
+  
+
 
diff --git a/src/MaksIT.Core.Tests/Sagas/LocalSagaTests.cs b/src/MaksIT.Core.Tests/Sagas/LocalSagaTests.cs
new file mode 100644
index 0000000..6e3230d
--- /dev/null
+++ b/src/MaksIT.Core.Tests/Sagas/LocalSagaTests.cs
@@ -0,0 +1,190 @@
+using MaksIT.Core.Logging;
+using MaksIT.Core.Sagas;
+using Microsoft.Extensions.Logging;
+
+namespace MaksIT.Core.Tests.Sagas;
+
+public class LocalSagaTests
+{
+    [Fact]
+    public async Task LocalSagaBuilder_ShouldBuildSagaWithSteps()
+    {
+        // Arrange
+        var logger = LoggerHelper.CreateConsoleLogger();
+        var builder = new LocalSagaBuilder().WithLogger(logger);
+        var stepExecuted = false;
+
+        builder.AddAction(
+            "TestStep",
+            async (ctx, ct) =>
+            {
+                stepExecuted = true;
+                await Task.CompletedTask;
+            });
+
+        var saga = builder.Build();
+
+        // Act
+        await saga.ExecuteAsync();
+
+        // Assert
+        Assert.True(stepExecuted, "The step should have been executed.");
+    }
+
+    [Fact]
+    public async Task LocalSaga_ShouldCompensateOnFailure()
+    {
+        // Arrange
+        var logger = LoggerHelper.CreateConsoleLogger();
+        var builder = new LocalSagaBuilder().WithLogger(logger);
+        var compensationCalled = false;
+
+        builder.AddAction(
+            "FailingStep",
+            async (ctx, ct) =>
+            {
+                throw new InvalidOperationException("Step failed");
+            },
+            async (ctx, ct) =>
+            {
+                compensationCalled = true;
+                await Task.CompletedTask;
+            });
+
+        var saga = builder.Build();
+
+        // Act & Assert
+        await Assert.ThrowsAsync(() => saga.ExecuteAsync());
+        Assert.True(compensationCalled, "Compensation should have been called.");
+    }
+
+    [Fact]
+    public async Task LocalSaga_ShouldSkipConditionalSteps()
+    {
+        // Arrange
+        var logger = LoggerHelper.CreateConsoleLogger();
+        var builder = new LocalSagaBuilder().WithLogger(logger);
+        var stepExecuted = false;
+
+        builder.AddActionIf(
+            ctx => false,
+            "SkippedStep",
+            async (ctx, ct) =>
+            {
+                stepExecuted = true;
+                await Task.CompletedTask;
+            });
+
+        var saga = builder.Build();
+
+        // Act
+        await saga.ExecuteAsync();
+
+        // Assert
+        Assert.False(stepExecuted, "The step should have been skipped.");
+    }
+
+    [Fact]
+    public async Task LocalSaga_ShouldLogExecution()
+    {
+        // Arrange
+        var logger = LoggerHelper.CreateConsoleLogger();
+        var builder = new LocalSagaBuilder().WithLogger(logger);
+
+        builder.AddAction(
+            "LoggingStep",
+            async (ctx, ct) => await Task.CompletedTask);
+
+        var saga = builder.Build();
+
+        // Act
+        await saga.ExecuteAsync();
+        // No assertion on logs, but output will be visible in test runner console
+    }
+
+    [Fact]
+    public async Task LocalSaga_ShouldRestorePreviousStateOnError()
+    {
+        // Arrange
+        var logger = LoggerHelper.CreateConsoleLogger();
+        var builder = new LocalSagaBuilder().WithLogger(logger);
+        var context = new LocalSagaContext();
+        context.Set("state", "initial");
+
+        builder.AddAction(
+            "ModifyStateStep",
+            async (ctx, ct) =>
+            {
+                ctx.Set("state", "modified");
+                await Task.CompletedTask;
+            },
+            async (ctx, ct) =>
+            {
+                ctx.Set("state", "initial");
+                await Task.CompletedTask;
+            });
+
+        builder.AddAction(
+            "FailingStep",
+            async (ctx, ct) =>
+            {
+                throw new InvalidOperationException("Step failed");
+            });
+
+        var saga = builder.Build();
+
+        // Act & Assert
+        await Assert.ThrowsAsync(() => saga.ExecuteAsync(context));
+        Assert.Equal("initial", context.Get("state"));
+    }
+
+    [Fact]
+    public async Task LocalSaga_ShouldHandleMultipleCompensations()
+    {
+        // Arrange
+        var logger = LoggerHelper.CreateConsoleLogger();
+        var builder = new LocalSagaBuilder().WithLogger(logger);
+        var context = new LocalSagaContext();
+        var compensationLog = new List();
+
+        builder.AddAction(
+            "Step1",
+            async (ctx, ct) =>
+            {
+                ctx.Set("step1", true);
+                await Task.CompletedTask;
+            },
+            async (ctx, ct) =>
+            {
+                compensationLog.Add("Step1 compensated");
+                await Task.CompletedTask;
+            });
+
+        builder.AddAction(
+            "Step2",
+            async (ctx, ct) =>
+            {
+                ctx.Set("step2", true);
+                await Task.CompletedTask;
+            },
+            async (ctx, ct) =>
+            {
+                compensationLog.Add("Step2 compensated");
+                await Task.CompletedTask;
+            });
+
+        builder.AddAction(
+            "FailingStep",
+            async (ctx, ct) =>
+            {
+                throw new InvalidOperationException("Step failed");
+            });
+
+        var saga = builder.Build();
+
+        // Act & Assert
+        await Assert.ThrowsAsync(() => saga.ExecuteAsync(context));
+        Assert.Contains("Step2 compensated", compensationLog);
+        Assert.Contains("Step1 compensated", compensationLog);
+    }
+}
diff --git a/src/MaksIT.Core.Tests/TestHostEnvironment.cs b/src/MaksIT.Core.Tests/TestHostEnvironment.cs
new file mode 100644
index 0000000..a35f8f9
--- /dev/null
+++ b/src/MaksIT.Core.Tests/TestHostEnvironment.cs
@@ -0,0 +1,15 @@
+using Microsoft.Extensions.FileProviders;
+using Microsoft.Extensions.Hosting;
+
+namespace MaksIT.Core.Tests;
+
+/// 
+/// Simple implementation of IHostEnvironment for testing purposes.
+/// 
+public class TestHostEnvironment : IHostEnvironment
+{
+    public string EnvironmentName { get; set; } = Environments.Production;
+    public string ApplicationName { get; set; } = "";
+    public string ContentRootPath { get; set; } = "";
+    public IFileProvider ContentRootFileProvider { get; set; } = new NullFileProvider();
+}
\ No newline at end of file
diff --git a/src/MaksIT.Core/MaksIT.Core.csproj b/src/MaksIT.Core/MaksIT.Core.csproj
index afcced1..d2c2576 100644
--- a/src/MaksIT.Core/MaksIT.Core.csproj
+++ b/src/MaksIT.Core/MaksIT.Core.csproj
@@ -8,7 +8,7 @@
 
     
     MaksIT.Core
-    1.4.7
+    1.4.8
     Maksym Sadovnychyy
     MAKS-IT
     MaksIT.Core
diff --git a/src/MaksIT.Core/Sagas/LocalSaga.cs b/src/MaksIT.Core/Sagas/LocalSaga.cs
new file mode 100644
index 0000000..84c254c
--- /dev/null
+++ b/src/MaksIT.Core/Sagas/LocalSaga.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace MaksIT.Core.Sagas;
+/// 
+/// Executable local saga with LIFO compensation on failure.
+/// 
+public sealed class LocalSaga {
+  private readonly IReadOnlyList _pipeline;
+  private readonly ILogger _logger;
+
+  internal LocalSaga(
+    IReadOnlyList pipeline,
+    ILogger logger) {
+    _pipeline = pipeline;
+    _logger = logger;
+  }
+
+  public async Task ExecuteAsync(LocalSagaContext? context = null, CancellationToken cancellationToken = default)
+  {
+      var ctx = context ?? new LocalSagaContext();
+      var executedStack = new Stack();
+
+      for (int i = 0; i < _pipeline.Count; i++)
+      {
+          cancellationToken.ThrowIfCancellationRequested();
+
+          var step = _pipeline[i];
+          try
+          {
+              _logger.LogInformation($"LocalSaga: executing step [{i + 1}/{_pipeline.Count}] '{step.Name}'");
+              var ran = await step.ExecuteAsync(ctx, cancellationToken);
+              if (ran)
+                  executedStack.Push(step); // Ensure step is pushed if it ran successfully
+              else
+                  _logger.LogInformation($"LocalSaga: skipped step '{step.Name}'");
+          }
+          catch (Exception ex)
+          {
+              _logger.LogError(ex, $"LocalSaga: step '{step.Name}' failed");
+              executedStack.Push(step); // Push the step to ensure compensation is triggered
+              await CompensateAsync(executedStack, ctx, cancellationToken);
+              throw;
+          }
+      }
+
+      _logger.LogInformation("LocalSaga: completed successfully");
+  }
+
+  private async Task CompensateAsync(
+    Stack executedStack,
+    LocalSagaContext ctx,
+    CancellationToken ct) {
+    _logger.LogInformation("LocalSaga: starting compensation");
+
+    var compensationErrors = new List();
+    int totalSteps = executedStack.Count;
+
+    try
+    {
+        while (executedStack.Count > 0)
+        {
+            var step = executedStack.Pop();
+            try
+            {
+                _logger.LogInformation($"LocalSaga: compensating step '{step.Name}' ({totalSteps - executedStack.Count}/{totalSteps})");
+                await step.CompensateAsync(ctx, ct);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, $"LocalSaga: compensation of step '{step.Name}' failed");
+                compensationErrors.Add(ex);
+            }
+        }
+    }
+    finally
+    {
+        _logger.LogInformation("LocalSaga: compensation finished");
+    }
+
+    if (compensationErrors.Count > 0)
+        throw new AggregateException("One or more compensation steps failed.", compensationErrors);
+  }
+}
\ No newline at end of file
diff --git a/src/MaksIT.Core/Sagas/LocalSagaBuilder.cs b/src/MaksIT.Core/Sagas/LocalSagaBuilder.cs
new file mode 100644
index 0000000..4083d54
--- /dev/null
+++ b/src/MaksIT.Core/Sagas/LocalSagaBuilder.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace MaksIT.Core.Sagas;
+
+/// 
+/// Fluent builder to compose a local saga (exception-based failures).
+/// 
+public sealed class LocalSagaBuilder {
+  private readonly List _pipeline = new();
+  private ILogger? _logger;
+
+  public LocalSagaBuilder WithLogger(ILogger logger) {
+    _logger = logger;
+    return this;
+  }
+
+  public LocalSagaBuilder AddAction(
+    string name,
+    Func execute,
+    Func? compensate = null) {
+    _pipeline.Add(new LocalSagaStep(
+      name,
+      async (c, ct) => { await execute(c, ct); return Unit.Value; },
+      compensate,
+      predicate: null,
+      outputKey: null));
+    return this;
+  }
+
+  public LocalSagaBuilder AddActionIf(
+    Func predicate,
+    string name,
+    Func execute,
+    Func? compensate = null) {
+    _pipeline.Add(new LocalSagaStep(
+      $"[conditional] {name}",
+      async (c, ct) => { await execute(c, ct); return Unit.Value; },
+      compensate,
+      predicate,
+      outputKey: null));
+    return this;
+  }
+
+  public LocalSagaBuilder AddStep(
+    string name,
+    Func> execute,
+    string? outputKey = null,
+    Func? compensate = null) {
+    _pipeline.Add(new LocalSagaStep(name, execute, compensate, predicate: null, outputKey: outputKey));
+    return this;
+  }
+
+  public LocalSagaBuilder AddStepIf(
+    Func predicate,
+    string name,
+    Func> execute,
+    string? outputKey = null,
+    Func? compensate = null) {
+    _pipeline.Add(new LocalSagaStep($"[conditional] {name}", execute, compensate, predicate, outputKey));
+    return this;
+  }
+
+  public LocalSaga Build() {
+    if (_logger == null)
+      throw new InvalidOperationException("Logger must be provided via WithLogger().");
+    return new LocalSaga(_pipeline, _logger);
+  }
+}
\ No newline at end of file
diff --git a/src/MaksIT.Core/Sagas/LocalSagaContext.cs b/src/MaksIT.Core/Sagas/LocalSagaContext.cs
new file mode 100644
index 0000000..c8b0645
--- /dev/null
+++ b/src/MaksIT.Core/Sagas/LocalSagaContext.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MaksIT.Core.Sagas;
+
+/// 
+/// Shared context to pass values between steps without tight coupling.
+/// 
+public sealed class LocalSagaContext {
+  private readonly Dictionary _bag = new(StringComparer.Ordinal);
+
+  public T? Get(string key) {
+    return _bag.TryGetValue(key, out var v) && v is T t ? t : default;
+  }
+
+  public LocalSagaContext Set(string key, T value) {
+    _bag[key] = value;
+    return this;
+  }
+
+  public bool Contains(string key) => _bag.ContainsKey(key);
+}
\ No newline at end of file
diff --git a/src/MaksIT.Core/Sagas/LocalSagaStep.cs b/src/MaksIT.Core/Sagas/LocalSagaStep.cs
new file mode 100644
index 0000000..1af047a
--- /dev/null
+++ b/src/MaksIT.Core/Sagas/LocalSagaStep.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+
+namespace MaksIT.Core.Sagas;
+
+/// 
+/// Internal non-generic step interface to unify generic steps.
+/// 
+internal interface ILocalSagaStep {
+  string Name { get; }
+  Task ExecuteAsync(LocalSagaContext ctx, CancellationToken ct);
+  Task CompensateAsync(LocalSagaContext ctx, CancellationToken ct);
+}
+
+
+/// 
+/// Generic step with a result that can optionally be stored into the context.
+/// Execution returns true if this step actually ran (useful for conditional steps).
+/// 
+internal sealed class LocalSagaStep : ILocalSagaStep {
+  public string Name { get; }
+  public Func> Execute { get; }
+  public Func? Compensate { get; }
+  public Func? Predicate { get; }
+  public string? OutputKey { get; }
+
+  public LocalSagaStep(
+    string name,
+    Func> execute,
+    Func? compensate,
+    Func? predicate,
+    string? outputKey) {
+    Name = name;
+    Execute = execute;
+    Compensate = compensate;
+    Predicate = predicate;
+    OutputKey = outputKey;
+  }
+
+  public async Task ExecuteAsync(LocalSagaContext ctx, CancellationToken ct) {
+    if (Predicate != null && !Predicate(ctx))
+      return false;
+
+    var result = await Execute(ctx, ct);
+    if (OutputKey != null)
+      ctx.Set(OutputKey, result);
+    return true;
+  }
+
+  public async Task CompensateAsync(LocalSagaContext ctx, CancellationToken ct) {
+    if (Compensate != null)
+      await Compensate(ctx, ct);
+  }
+}
\ No newline at end of file
diff --git a/src/MaksIT.Core/Sagas/Unit.cs b/src/MaksIT.Core/Sagas/Unit.cs
new file mode 100644
index 0000000..c5f276b
--- /dev/null
+++ b/src/MaksIT.Core/Sagas/Unit.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MaksIT.Core.Sagas;
+/// 
+/// A simple unit type for steps that do not return a value.
+/// 
+public readonly struct Unit {
+  public static readonly Unit Value = new Unit();
+}
diff --git a/src/README.md b/src/README.md
new file mode 100644
index 0000000..5da7709
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,811 @@
+# MaksIT.Core Library Documentation
+
+## Table of Contents
+
+- [Abstractions](#abstractions)
+  - [Base Classes](#base-classes)
+  - [Enumeration](#enumeration)
+- [Extensions](#extensions)
+  - [Expression Extensions](#expression-extensions)
+  - [DateTime Extensions](#datetime-extensions)
+  - [String Extensions](#string-extensions)
+  - [Object Extensions](#object-extensions)
+  - [DataTable Extensions](#datatable-extensions)
+  - [Guid Extensions](#guid-extensions)
+- [Logging](#logging)
+- [Networking](#networking)
+  - [Network Connection](#network-connection)
+  - [Ping Port](#ping-port)
+- [Security](#security)
+  - [AES-GCM Utility](#aes-gcm-utility)
+  - [Base32 Encoder](#base32-encoder)
+  - [Checksum Utility](#checksum-utility)
+  - [Password Hasher](#password-hasher)
+  - [JWT Generator](#jwt-generator)
+  - [TOTP Generator](#totp-generator)
+- [Web API Models](#web-api-models)
+- [Sagas](#sagas)
+- [Others](#others)
+  - [Culture](#culture)
+  - [Environment Variables](#environment-variables)
+  - [File System](#file-system)
+  - [Processes](#processes)
+
+
+## Abstractions
+
+### Base Classes
+
+The following base classes in the `MaksIT.Core.Abstractions` namespace provide a foundation for implementing domain, DTO, and Web API models, ensuring consistency and maintainability in application design.
+
+---
+
+##### 1. **`DomainObjectBase`**
+
+###### Summary
+Represents the base class for all domain objects in the application.
+
+###### Purpose
+- Serves as the foundation for all domain objects.
+- Provides a place to include shared logic or properties for domain-level entities in the future.
+
+---
+
+##### 2. **`DomainDocumentBase`**
+
+###### Summary
+Represents a base class for domain documents with a unique identifier.
+
+###### Purpose
+- Extends `DomainObjectBase` to include an identifier.
+- Provides a common structure for domain entities that need unique IDs.
+
+###### Example Usage
+```csharp
+public class UserDomainDocument : DomainDocumentBase {
+    public UserDomainDocument(Guid id) : base(id) {
+    }
+}
+```
+
+---
+
+##### 3. **`DtoObjectBase`**
+
+###### Summary
+Represents the base class for all Data Transfer Objects (DTOs).
+
+###### Purpose
+- Serves as the foundation for all DTOs.
+- Provides a place to include shared logic or properties for DTOs in the future.
+
+---
+
+##### 4. **`DtoDocumentBase`**
+
+###### Summary
+Represents a base class for DTOs with a unique identifier.
+
+###### Purpose
+- Extends `DtoObjectBase` to include an identifier.
+- Provides a common structure for DTOs that need unique IDs.
+
+###### Example Usage
+```csharp
+public class UserDto : DtoDocumentBase {
+    public required string Name { get; set; }
+}
+```
+
+---
+
+##### 5. **`RequestModelBase`**
+
+###### Summary
+Represents the base class for Web API request models.
+
+###### Purpose
+- Serves as a foundation for request models used in Web API endpoints.
+- Provides a common structure for request validation or shared properties.
+
+###### Example Usage
+```csharp
+public class CreateUserRequest : RequestModelBase {
+    public required string Name { get; set; }
+}
+```
+
+---
+
+##### 6. **`ResponseModelBase`**
+
+###### Summary
+Represents the base class for Web API response models.
+
+###### Purpose
+- Serves as a foundation for response models returned by Web API endpoints.
+- Provides a common structure for standardizing API responses.
+
+###### Example Usage
+```csharp
+public class UserResponse : ResponseModelBase {
+    public required Guid Id { get; set; }
+    public required string Name { get; set; }
+}
+```
+
+---
+
+#### Features and Benefits
+
+1. **Consistency**:
+   - Ensures a uniform structure for domain, DTO, and Web API models.
+
+2. **Extensibility**:
+   - Base classes can be extended to include shared properties or methods as needed.
+
+3. **Type Safety**:
+   - Generic identifiers (`T`) ensure type safety for domain documents and DTOs.
+
+4. **Reusability**:
+   - Common logic or properties can be added to base classes and reused across the application.
+
+---
+
+#### Example End-to-End Usage
+
+```csharp
+// Domain Class
+public class ProductDomain : DomainDocumentBase {
+    public ProductDomain(int id) : base(id) { }
+    public string Name { get; set; } = string.Empty;
+}
+
+// DTO Class
+public class ProductDto : DtoDocumentBase {
+    public required string Name { get; set; }
+}
+
+// Web API Request Model
+public class CreateProductRequest : RequestModelBase {
+    public required string Name { get; set; }
+}
+
+// Web API Response Model
+public class ProductResponse : ResponseModelBase {
+    public required int Id { get; set; }
+    public required string Name { get; set; }
+}
+```
+
+---
+
+#### Best Practices
+
+1. **Keep Base Classes Lightweight**:
+   - Avoid adding unnecessary properties or methods to base classes.
+
+2. **Encapsulation**:
+   - Use base classes to enforce encapsulation and shared behavior across entities.
+
+3. **Validation**:
+   - Extend `RequestModelBase` or `ResponseModelBase` to include validation logic if needed.
+
+---
+
+This structure promotes clean code principles, reducing redundancy and improving maintainability across the application layers.
+
+---
+
+### Enumeration
+
+The `Enumeration` class in the `MaksIT.Core.Abstractions` namespace provides a base class for creating strongly-typed enumerations. It enables you to define enumerable constants with additional functionality, such as methods for querying, comparing, and parsing enumerations.
+
+---
+
+#### Features and Benefits
+
+1. **Strongly-Typed Enumerations**:
+   - Combines the clarity of enums with the extensibility of classes.
+   - Supports additional fields, methods, or logic as needed.
+
+2. **Reflection Support**:
+   - Dynamically retrieve all enumeration values with `GetAll`.
+
+3. **Parsing Capabilities**:
+   - Retrieve enumeration values by ID or display name.
+
+4. **Comparison and Equality**:
+   - Fully implements equality and comparison operators for use in collections and sorting.
+
+---
+
+#### Example Usage
+
+#### Defining an Enumeration
+```csharp
+public class MyEnumeration : Enumeration {
+    public static readonly MyEnumeration Value1 = new(1, "Value One");
+    public static readonly MyEnumeration Value2 = new(2, "Value Two");
+
+    private MyEnumeration(int id, string name) : base(id, name) { }
+}
+```
+
+#### Retrieving All Values
+```csharp
+var allValues = Enumeration.GetAll();
+allValues.ToList().ForEach(Console.WriteLine);
+```
+
+#### Parsing by ID or Name
+```csharp
+var valueById = Enumeration.FromValue(1);
+var valueByName = Enumeration.FromDisplayName("Value One");
+
+Console.WriteLine(valueById); // Output: Value One
+Console.WriteLine(valueByName); // Output: Value One
+```
+
+#### Comparing Enumeration Values
+```csharp
+var difference = Enumeration.AbsoluteDifference(MyEnumeration.Value1, MyEnumeration.Value2);
+Console.WriteLine($"Absolute Difference: {difference}"); // Output: 1
+```
+
+#### Using in Collections
+```csharp
+var values = new List { MyEnumeration.Value2, MyEnumeration.Value1 };
+values.Sort(); // Orders by ID
+```
+
+---
+
+#### Best Practices
+
+1. **Extend for Specific Enums**:
+   - Create specific subclasses for each enumeration type.
+
+2. **Avoid Duplicates**:
+   - Ensure unique IDs and names for each enumeration value.
+
+3. **Use Reflection Sparingly**:
+   - Avoid calling `GetAll` in performance-critical paths.
+
+---
+
+The `Enumeration` class provides a powerful alternative to traditional enums, offering flexibility and functionality for scenarios requiring additional metadata or logic.
+
+---
+
+### Extensions
+
+### Guid Extensions
+
+The `GuidExtensions` class provides methods for working with `Guid` values, including converting them to nullable types.
+
+---
+
+#### Features
+
+1. **Convert to Nullable**:
+   - Convert a `Guid` to a nullable `Guid?`, returning `null` if the `Guid` is empty.
+
+---
+
+#### Example Usage
+
+##### Converting to Nullable
+```csharp
+Guid id = Guid.NewGuid();
+Guid? nullableId = id.ToNullable();
+```
+
+---
+
+### Expression Extensions
+
+The `ExpressionExtensions` class provides utility methods for combining and manipulating LINQ expressions. These methods are particularly useful for building dynamic queries in a type-safe manner.
+
+---
+
+#### Features
+
+1. **Combine Expressions**:
+   - Combine two expressions using logical operators like `AndAlso` and `OrElse`.
+
+2. **Negate Expressions**:
+   - Negate an expression using the `Not` method.
+
+3. **Batch Processing**:
+   - Divide a collection into smaller batches for processing.
+
+---
+
+#### Example Usage
+
+##### Combining Expressions
+```csharp
+Expression> isEven = x => x % 2 == 0;
+Expression> isPositive = x => x > 0;
+
+var combined = isEven.AndAlso(isPositive);
+var result = combined.Compile()(4); // True
+```
+
+##### Negating Expressions
+```csharp
+Expression> isEven = x => x % 2 == 0;
+var notEven = isEven.Not();
+var result = notEven.Compile()(3); // True
+```
+
+---
+
+### DateTime Extensions
+
+The `DateTimeExtensions` class provides methods for manipulating and querying `DateTime` objects. These methods simplify common date-related operations.
+
+---
+
+#### Features
+
+1. **Add Workdays**:
+   - Add a specified number of workdays to a date, excluding weekends and holidays.
+
+2. **Find Specific Dates**:
+   - Find the next occurrence of a specific day of the week.
+
+3. **Month and Year Boundaries**:
+   - Get the start or end of the current month or year.
+
+---
+
+#### Example Usage
+
+##### Adding Workdays
+```csharp
+DateTime today = DateTime.Today;
+DateTime futureDate = today.AddWorkdays(5);
+```
+
+##### Finding the Next Monday
+```csharp
+DateTime today = DateTime.Today;
+DateTime nextMonday = today.NextWeekday(DayOfWeek.Monday);
+```
+
+---
+
+### String Extensions
+
+The `StringExtensions` class provides a wide range of methods for string manipulation, validation, and conversion.
+
+---
+
+#### Features
+
+1. **Pattern Matching**:
+   - Check if a string matches a pattern using SQL-like wildcards.
+
+2. **Substring Extraction**:
+   - Extract substrings from the left, right, or middle of a string.
+
+3. **Type Conversion**:
+   - Convert strings to various types, such as integers, booleans, and enums.
+
+---
+
+#### Example Usage
+
+##### Pattern Matching
+```csharp
+bool matches = "example".Like("exa*e"); // True
+```
+
+##### Substring Extraction
+```csharp
+string result = "example".Left(3); // "exa"
+```
+
+---
+
+### Object Extensions
+
+The `ObjectExtensions` class provides methods for serializing objects to JSON strings and deserializing JSON strings back to objects.
+
+---
+
+#### Features
+
+1. **JSON Serialization**:
+   - Convert objects to JSON strings.
+
+2. **JSON Deserialization**:
+   - Convert JSON strings back to objects.
+
+---
+
+#### Example Usage
+
+##### Serialization
+```csharp
+var person = new { Name = "John", Age = 30 };
+string json = person.ToJson();
+```
+
+##### Deserialization
+```csharp
+var person = json.ToObject();
+```
+
+---
+
+### DataTable Extensions
+
+The `DataTableExtensions` class provides methods for working with `DataTable` objects, such as counting duplicate rows and retrieving distinct records.
+
+---
+
+#### Features
+
+1. **Count Duplicates**:
+   - Count duplicate rows between two `DataTable` instances.
+
+2. **Retrieve Distinct Records**:
+   - Get distinct rows based on specified columns.
+
+---
+
+#### Example Usage
+
+##### Counting Duplicates
+```csharp
+int duplicateCount = table1.DuplicatesCount(table2);
+```
+
+##### Retrieving Distinct Records
+```csharp
+DataTable distinctTable = table.DistinctRecords(new[] { "Name", "Age" });
+```
+
+---
+
+## Logging
+
+The `Logging` namespace provides a custom file-based logging implementation that integrates with the `Microsoft.Extensions.Logging` framework.
+
+---
+
+#### Features
+
+1. **File-Based Logging**:
+   - Log messages to a specified file.
+
+2. **Log Levels**:
+   - Supports all standard log levels.
+
+3. **Thread Safety**:
+   - Ensures thread-safe writes to the log file.
+
+---
+
+#### Example Usage
+
+```csharp
+var services = new ServiceCollection();
+services.AddLogging(builder => builder.AddFile("logs.txt"));
+
+var logger = services.BuildServiceProvider().GetRequiredService>();
+logger.LogInformation("Logging to file!");
+```
+
+---
+
+## Networking
+
+### Network Connection
+
+The `NetworkConnection` class provides methods for managing connections to network shares on Windows.
+
+---
+
+#### Features
+
+1. **Connect to Network Shares**:
+   - Establish connections to shared network resources.
+
+2. **Error Handling**:
+   - Provides detailed error messages for connection failures.
+
+---
+
+#### Example Usage
+
+```csharp
+var credentials = new NetworkCredential("username", "password");
+if (NetworkConnection.TryCreate(logger, "\\server\share", credentials, out var connection, out var error)) {
+    connection.Dispose();
+}
+```
+
+---
+
+### Ping Port
+
+The `PingPort` class provides methods for checking the reachability of a host on specified TCP or UDP ports.
+
+---
+
+#### Features
+
+1. **TCP Port Checking**:
+   - Check if a TCP port is reachable.
+
+2. **UDP Port Checking**:
+   - Check if a UDP port is reachable.
+
+---
+
+#### Example Usage
+
+##### Checking a TCP Port
+```csharp
+if (PingPort.TryHostPort("example.com", 80, out var error)) {
+    Console.WriteLine("Port is reachable.");
+}
+```
+
+---
+
+## Security
+
+### AES-GCM Utility
+
+The `AESGCMUtility` class provides methods for encrypting and decrypting data using AES-GCM.
+
+---
+
+#### Features
+
+1. **Secure Encryption**:
+   - Encrypt data with AES-GCM.
+
+2. **Data Integrity**:
+   - Ensure data integrity with authentication tags.
+
+---
+
+#### Example Usage
+
+##### Encrypting Data
+```csharp
+var key = AESGCMUtility.GenerateKeyBase64();
+AESGCMUtility.TryEncryptData(data, key, out var encryptedData, out var error);
+```
+
+---
+
+### Base32 Encoder
+
+The `Base32Encoder` class provides methods for encoding and decoding data in Base32 format.
+
+---
+
+#### Features
+
+1. **Encoding**:
+   - Encode binary data to Base32.
+
+2. **Decoding**:
+   - Decode Base32 strings to binary data.
+
+---
+
+#### Example Usage
+
+##### Encoding Data
+```csharp
+Base32Encoder.TryEncode(data, out var encoded, out var error);
+```
+
+---
+
+### Checksum Utility
+
+The `ChecksumUtility` class provides methods for calculating and verifying CRC32 checksums.
+
+---
+
+#### Features
+
+1. **Checksum Calculation**:
+   - Calculate CRC32 checksums for data.
+
+2. **Checksum Verification**:
+   - Verify data integrity using CRC32 checksums.
+
+---
+
+#### Example Usage
+
+##### Calculating a Checksum
+```csharp
+ChecksumUtility.TryCalculateCRC32Checksum(data, out var checksum, out var error);
+```
+
+---
+
+### Password Hasher
+
+The `PasswordHasher` class provides methods for securely hashing and validating passwords.
+
+---
+
+#### Features
+
+1. **Salted Hashing**:
+   - Hash passwords with a unique salt.
+
+2. **Validation**:
+   - Validate passwords against stored hashes.
+
+---
+
+#### Example Usage
+
+##### Hashing a Password
+```csharp
+PasswordHasher.TryCreateSaltedHash("password", out var hash, out var error);
+```
+
+---
+
+### JWT Generator
+
+The `JwtGenerator` class provides methods for generating and validating JSON Web Tokens (JWTs).
+
+---
+
+#### Features
+
+1. **Token Generation**:
+   - Generate JWTs with claims and metadata.
+
+2. **Token Validation**:
+   - Validate JWTs against a secret.
+
+---
+
+#### Example Usage
+
+##### Generating a Token
+```csharp
+JwtGenerator.TryGenerateToken(secret, issuer, audience, 60, "user", roles, out var token, out var error);
+```
+
+---
+
+### TOTP Generator
+
+The `TotpGenerator` class provides methods for generating and validating Time-Based One-Time Passwords (TOTP).
+
+---
+
+#### Features
+
+1. **TOTP Generation**:
+   - Generate TOTPs based on shared secrets.
+
+2. **TOTP Validation**:
+   - Validate TOTPs with time tolerance.
+
+---
+
+#### Example Usage
+
+##### Generating a TOTP
+```csharp
+TotpGenerator.TryGenerate(secret, TotpGenerator.GetCurrentTimeStepNumber(), out var totp, out var error);
+```
+
+---
+
+## Others
+
+### Culture
+
+The `Culture` class provides methods for dynamically setting the culture for the current thread.
+
+---
+
+#### Features
+
+1. **Dynamic Culture Setting**:
+   - Change the culture for the current thread.
+
+---
+
+#### Example Usage
+
+##### Setting the Culture
+```csharp
+Culture.TrySet("fr-FR", out var error);
+```
+
+---
+
+### Environment Variables
+
+The `EnvVar` class provides methods for managing environment variables.
+
+---
+
+#### Features
+
+1. **Add to PATH**:
+   - Add directories to the `PATH` environment variable.
+
+2. **Set and Unset Variables**:
+   - Manage environment variables at different scopes.
+
+---
+
+#### Example Usage
+
+##### Adding to PATH
+```csharp
+EnvVar.TryAddToPath("/usr/local/bin", out var error);
+```
+
+---
+
+### File System
+
+The `FileSystem` class provides methods for working with files and directories.
+
+---
+
+#### Features
+
+1. **Copy Files and Folders**:
+   - Copy files or directories to a target location.
+
+2. **Delete Files and Folders**:
+   - Delete files or directories.
+
+---
+
+#### Example Usage
+
+##### Copying Files
+```csharp
+FileSystem.TryCopyToFolder("source", "destination", true, out var error);
+```
+
+---
+
+### Processes
+
+The `Processes` class provides methods for managing system processes.
+
+---
+
+#### Features
+
+1. **Start Processes**:
+   - Start new processes with optional arguments.
+
+2. **Kill Processes**:
+   - Terminate processes by name.
+
+---
+
+#### Example Usage
+
+##### Starting a Process
+```csharp
+Processes.TryStart("notepad.exe", "", 0, false, out var error);
+```
+
+---
\ No newline at end of file
diff --git a/src/Release-NuGetPackage.ps1 b/src/Release-NuGetPackage.ps1
index 8e69465..c978865 100644
--- a/src/Release-NuGetPackage.ps1
+++ b/src/Release-NuGetPackage.ps1
@@ -12,11 +12,20 @@ $nugetSource = "https://api.nuget.org/v3/index.json"
 $solutionDir = Split-Path -Parent $MyInvocation.MyCommand.Path
 $projectDir = "$solutionDir\MaksIT.Core"
 $outputDir = "$projectDir\bin\Release"
+$testProjectDir = "$solutionDir\MaksIT.Core.Tests"
 
 # Clean previous builds
 Write-Host "Cleaning previous builds..."
 dotnet clean $projectDir -c Release
 
+# Run tests
+Write-Host "Running tests..."
+dotnet test $testProjectDir -c Release --no-build
+if ($LASTEXITCODE -ne 0) {
+    Write-Host "Tests failed. Aborting release process."
+    exit 1
+}
+
 # Build the project
 Write-Host "Building the project..."
 dotnet build $projectDir -c Release