diff --git a/Domain/ArrayType.cs b/Domain/ArrayType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a3067d0b78cdff9a84bc7cfcc0a6b219cad8c6aa
--- /dev/null
+++ b/Domain/ArrayType.cs
@@ -0,0 +1,15 @@
+namespace Domain;
+
+public enum ArrayType
+{
+    Int,
+    Char,
+    Varchar
+}
+
+public static class ArrayTypeTranscript 
+{
+    public const string Int = "int";
+    public const string Char = "char";
+    public const string Varchar = "varchar";
+}
\ No newline at end of file
diff --git a/Domain/Domain.csproj b/Domain/Domain.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..f53c6e7ae89f09f9f46e425b802c1e542796f516
--- /dev/null
+++ b/Domain/Domain.csproj
@@ -0,0 +1,18 @@
+п»ї<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net9.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+    <RootNamespace>Domain</RootNamespace>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Folder Include="Service\" />
+  </ItemGroup>
+
+</Project>
diff --git a/Domain/Exception/VirtualMemoryAlreadyInitializedException.cs b/Domain/Exception/VirtualMemoryAlreadyInitializedException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..97b0bb885b6a3c38e9308f8183430832346384a8
--- /dev/null
+++ b/Domain/Exception/VirtualMemoryAlreadyInitializedException.cs
@@ -0,0 +1,3 @@
+namespace Domain.Exception;
+
+public class VirtualMemoryAlreadyInitializedException: InvalidOperationException;
\ No newline at end of file
diff --git a/Domain/Exception/VirtualMemoryNotInitializedException.cs b/Domain/Exception/VirtualMemoryNotInitializedException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ede7fa3632d73b6d619135da5c3ca7712b03c8aa
--- /dev/null
+++ b/Domain/Exception/VirtualMemoryNotInitializedException.cs
@@ -0,0 +1,3 @@
+namespace Domain.Exception;
+
+public class VirtualMemoryNotInitializedException: InvalidOperationException;
\ No newline at end of file
diff --git a/Domain/UseCase/ICreateCharVirtualMemoryUseCase.cs b/Domain/UseCase/ICreateCharVirtualMemoryUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..46d39a3368f16a133a77500298ca17e3e837a0de
--- /dev/null
+++ b/Domain/UseCase/ICreateCharVirtualMemoryUseCase.cs
@@ -0,0 +1,6 @@
+namespace Domain.UseCase;
+
+public interface ICreateCharVirtualMemoryUseCase
+{
+    void Invoke(string fileName, int size, int fixedStringLength);
+}
\ No newline at end of file
diff --git a/Domain/UseCase/ICreateIntVirtualMemoryUseCase.cs b/Domain/UseCase/ICreateIntVirtualMemoryUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..02f92f6ac01a577076340fcaae9373e39ccdbc59
--- /dev/null
+++ b/Domain/UseCase/ICreateIntVirtualMemoryUseCase.cs
@@ -0,0 +1,6 @@
+namespace Domain.UseCase;
+
+public interface ICreateIntVirtualMemoryUseCase
+{
+    void Invoke(string fileName, int size);
+}
\ No newline at end of file
diff --git a/Domain/UseCase/ICreateVarcharVirtualMemoryUseCase.cs b/Domain/UseCase/ICreateVarcharVirtualMemoryUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..96502ff9c0106796e2bbd6b3e2db571042d2a442
--- /dev/null
+++ b/Domain/UseCase/ICreateVarcharVirtualMemoryUseCase.cs
@@ -0,0 +1,6 @@
+namespace Domain.UseCase;
+
+public interface ICreateVarcharVirtualMemoryUseCase
+{
+    void Invoke(string fileName, int size, int maxStringLength);
+}
\ No newline at end of file
diff --git a/Domain/UseCase/IExitUseCase.cs b/Domain/UseCase/IExitUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d5eb5ee63d3585a5c3bf9946c431750f0cb627ab
--- /dev/null
+++ b/Domain/UseCase/IExitUseCase.cs
@@ -0,0 +1,5 @@
+namespace Domain.UseCase;
+public interface IExitUseCase
+{
+    void Invoke();
+}
\ No newline at end of file
diff --git a/Domain/UseCase/IGetActiveArrayTypeUseCase.cs b/Domain/UseCase/IGetActiveArrayTypeUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..18b037dcd4bf3018ba202d2148e910d44b0a60f6
--- /dev/null
+++ b/Domain/UseCase/IGetActiveArrayTypeUseCase.cs
@@ -0,0 +1,6 @@
+namespace Domain.UseCase;
+
+public interface IGetActiveArrayTypeUseCase
+{
+    ArrayType? Invoke();
+}
\ No newline at end of file
diff --git a/Domain/UseCase/IGetItemByIndexUseCase.cs b/Domain/UseCase/IGetItemByIndexUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6fc0f9a3af3886b50ac52b38122865ee333a2f70
--- /dev/null
+++ b/Domain/UseCase/IGetItemByIndexUseCase.cs
@@ -0,0 +1,6 @@
+namespace Domain.UseCase;
+
+public interface IGetItemByIndexUseCase
+{
+    string Invoke(int index);
+}
\ No newline at end of file
diff --git a/Domain/UseCase/IInputIntUseCase.cs b/Domain/UseCase/IInputIntUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a8988bf9c84022968123f74dd8d7059b6b1f6b71
--- /dev/null
+++ b/Domain/UseCase/IInputIntUseCase.cs
@@ -0,0 +1,6 @@
+namespace Domain.UseCase;
+
+public interface IInputIntUseCase
+{
+    void Invoke(int index, int value);
+}
\ No newline at end of file
diff --git a/Domain/UseCase/IInputUseCase.cs b/Domain/UseCase/IInputUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e2de582f6c514ecf98d5e01e15d7a5400c274169
--- /dev/null
+++ b/Domain/UseCase/IInputUseCase.cs
@@ -0,0 +1,6 @@
+namespace Domain.UseCase;
+
+public interface IInputStringUseCase
+{
+    void Invoke(int index, string value);
+}
\ No newline at end of file
diff --git a/Lab1.Tests/Data/Service/InMemoryVirtualMemoryServiceTest.cs b/Lab1.Tests/Data/Service/InMemoryVirtualMemoryServiceTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1c725e874ce8f9f1349bf891642a80a4b9d15006
--- /dev/null
+++ b/Lab1.Tests/Data/Service/InMemoryVirtualMemoryServiceTest.cs
@@ -0,0 +1,109 @@
+using Domain;
+using Domain.Exception;
+using Lab1.Data.Service;
+using Lab1.Domain.Service;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using VM.Domain;
+
+namespace Lab1.Tests.Data.Service
+{
+    [TestClass]
+    public class InMemoryVirtualMemoryServiceTests
+    {
+        private Mock<IIntVirtualMemoryFactory> _intVirtualMemoryFactoryMock = null!;
+        private Mock<ICharVirtualMemoryFactory> _charVirtualMemoryFactoryMock = null!;
+        private Mock<IVarcharVirtualMemoryFactory> _varcharVirtualMemoryFactoryMock = null!;
+        private InMemoryVirtualMemoryService _service = null!;
+
+        private Mock<IVirtualMemory<int>> _intVirtualMemoryMock = null!;
+        private Mock<IVirtualMemory<string>> _charVirtualMemoryMock = null!;
+        private Mock<IVirtualMemory<string>> _varcharVirtualMemoryMock = null!;
+
+        [TestInitialize]
+        public void Setup()
+        {
+            _intVirtualMemoryFactoryMock = new Mock<IIntVirtualMemoryFactory>();
+            _charVirtualMemoryFactoryMock = new Mock<ICharVirtualMemoryFactory>();
+            _varcharVirtualMemoryFactoryMock = new Mock<IVarcharVirtualMemoryFactory>();
+
+            _service = new InMemoryVirtualMemoryService(
+                _intVirtualMemoryFactoryMock.Object,
+                _charVirtualMemoryFactoryMock.Object,
+                _varcharVirtualMemoryFactoryMock.Object
+            );
+
+            _intVirtualMemoryMock = new Mock<IVirtualMemory<int>>();
+            _charVirtualMemoryMock = new Mock<IVirtualMemory<string>>();
+            _varcharVirtualMemoryMock = new Mock<IVirtualMemory<string>>();
+        }
+        
+        [TestMethod]
+        [ExpectedException(typeof(VirtualMemoryAlreadyInitializedException))]
+        public void CreateCharVirtualMemory_ThrowsException_WhenAlreadyInitialized()
+        {
+            // Arrange
+            string fileName = "testfile";
+            int size = 1000;
+            int fixedStringLength = 20;
+
+            _service.CreateCharVirtualMemory(fileName, size, fixedStringLength);
+
+            // Act
+            _service.CreateCharVirtualMemory(fileName, size, fixedStringLength); // Should throw exception
+        }
+
+        [TestMethod]
+        public void CreateVarcharVirtualMemory_CreatesVarcharVirtualMemory_WhenNotInitialized()
+        {
+            // Arrange
+            string fileName = "testfile";
+            int size = 1000;
+            int maxStringLength = 50;
+
+            _varcharVirtualMemoryFactoryMock
+                .Setup(x => x.Create(fileName, size, maxStringLength))
+                .Returns(_varcharVirtualMemoryMock.Object);
+
+            // Act
+            _service.CreateVarcharVirtualMemory(fileName, size, maxStringLength);
+
+            // Assert
+            Assert.IsTrue(_service.IsActive);
+            Assert.AreEqual(ArrayType.Varchar, _service.ActiveArrayType);
+            _varcharVirtualMemoryFactoryMock.Verify(x => x.Create(fileName, size, maxStringLength), Times.Once);
+
+            _service.CloseVirtualMemory();
+
+            // Assert
+            Assert.IsFalse(_service.IsActive);
+            _varcharVirtualMemoryMock.Verify(x => x.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void CreateIntVirtualMemory_CreatesIntVirtualMemory_WhenNotInitialized()
+        {
+            // Arrange
+            string fileName = "testfile";
+            int size = 1000;
+
+            _intVirtualMemoryFactoryMock
+                .Setup(x => x.Create(fileName, size))
+                .Returns(_intVirtualMemoryMock.Object);
+
+            // Act
+            _service.CreateIntVirtualMemory(fileName, size);
+
+            // Assert
+            Assert.IsTrue(_service.IsActive);
+            Assert.AreEqual(ArrayType.Int, _service.ActiveArrayType);
+            _intVirtualMemoryFactoryMock.Verify(x => x.Create(fileName, size), Times.Once);
+            _service.CloseVirtualMemory();
+
+            // Assert
+            Assert.IsFalse(_service.IsActive);
+            _intVirtualMemoryMock.Verify(x => x.Dispose(), Times.Once);
+        }
+        
+    }
+}
\ No newline at end of file
diff --git a/Lab1.Tests/Lab1.Tests.csproj b/Lab1.Tests/Lab1.Tests.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..f72176eaa1de92f9bd0b0f6409a9ff36e2e2031b
--- /dev/null
+++ b/Lab1.Tests/Lab1.Tests.csproj
@@ -0,0 +1,24 @@
+п»ї<Project Sdk="Microsoft.NET.Sdk">
+
+    <PropertyGroup>
+        <TargetFramework>net9.0</TargetFramework>
+        <LangVersion>latest</LangVersion>
+        <ImplicitUsings>enable</ImplicitUsings>
+        <Nullable>enable</Nullable>
+        <IsPackable>false</IsPackable>
+    </PropertyGroup>
+    
+    <ItemGroup>
+        <PackageReference Include="JetBrains.Annotations" Version="2025.1.0-eap1"/>
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2"/>
+        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0"/>
+        <PackageReference Include="Moq" Version="4.20.72"/>
+        <PackageReference Include="MSTest.TestAdapter" Version="3.8.2"/>
+        <PackageReference Include="MSTest.TestFramework" Version="3.8.2"/>
+    </ItemGroup>
+    
+    <ItemGroup>
+      <ProjectReference Include="..\Lab1\Lab1.csproj" />
+    </ItemGroup>
+
+</Project>
diff --git a/Lab1.sln b/Lab1.sln
index f707e5c2d313331679ed5370ce5db7ca28b6059b..1a69ca188cab0b1c8b812eb9fa5fb48ae6d15d4e 100644
--- a/Lab1.sln
+++ b/Lab1.sln
@@ -2,6 +2,18 @@
 Microsoft Visual Studio Solution File, Format Version 12.00
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lab1", "Lab1\Lab1.csproj", "{2851C4FA-47FB-4B7B-A7F2-229EC08CA36C}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VM", "VM\VM.csproj", "{32D7C5DD-9647-43AC-A7C6-8323513073D0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VM.Tests", "VM.Tests\VM.Tests.csproj", "{0753A72A-6A76-4D02-81AF-B6548D8AEA41}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UI", "UI\UI.csproj", "{B0D69506-EF6C-4C37-B3E6-6D02EF1C8E14}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UI.Tests", "UI.Tests\UI.Tests.csproj", "{CFFBE5D7-BC91-4994-9BE4-0795E02E3EE7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Domain", "Domain\Domain.csproj", "{0062B734-4F10-4577-97BA-C1369C99754C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lab1.Tests", "Lab1.Tests\Lab1.Tests.csproj", "{75E2BDD0-6C46-4028-8CB2-4EAEA2B9FD27}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -12,5 +24,29 @@ Global
 		{2851C4FA-47FB-4B7B-A7F2-229EC08CA36C}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{2851C4FA-47FB-4B7B-A7F2-229EC08CA36C}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{2851C4FA-47FB-4B7B-A7F2-229EC08CA36C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{32D7C5DD-9647-43AC-A7C6-8323513073D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{32D7C5DD-9647-43AC-A7C6-8323513073D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{32D7C5DD-9647-43AC-A7C6-8323513073D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{32D7C5DD-9647-43AC-A7C6-8323513073D0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0753A72A-6A76-4D02-81AF-B6548D8AEA41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0753A72A-6A76-4D02-81AF-B6548D8AEA41}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0753A72A-6A76-4D02-81AF-B6548D8AEA41}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0753A72A-6A76-4D02-81AF-B6548D8AEA41}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B0D69506-EF6C-4C37-B3E6-6D02EF1C8E14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B0D69506-EF6C-4C37-B3E6-6D02EF1C8E14}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B0D69506-EF6C-4C37-B3E6-6D02EF1C8E14}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B0D69506-EF6C-4C37-B3E6-6D02EF1C8E14}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CFFBE5D7-BC91-4994-9BE4-0795E02E3EE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CFFBE5D7-BC91-4994-9BE4-0795E02E3EE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CFFBE5D7-BC91-4994-9BE4-0795E02E3EE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CFFBE5D7-BC91-4994-9BE4-0795E02E3EE7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0062B734-4F10-4577-97BA-C1369C99754C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0062B734-4F10-4577-97BA-C1369C99754C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0062B734-4F10-4577-97BA-C1369C99754C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0062B734-4F10-4577-97BA-C1369C99754C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{75E2BDD0-6C46-4028-8CB2-4EAEA2B9FD27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{75E2BDD0-6C46-4028-8CB2-4EAEA2B9FD27}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{75E2BDD0-6C46-4028-8CB2-4EAEA2B9FD27}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{75E2BDD0-6C46-4028-8CB2-4EAEA2B9FD27}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 EndGlobal
diff --git a/Lab1/Data/Service/CharVirtualMemoryFactory.cs b/Lab1/Data/Service/CharVirtualMemoryFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2d0411cb5807f57c0b30c0784dc0650f94ca70b3
--- /dev/null
+++ b/Lab1/Data/Service/CharVirtualMemoryFactory.cs
@@ -0,0 +1,19 @@
+using Lab1.Domain.Service;
+using VM.Domain;
+
+namespace Lab1.Data.Service;
+
+public class CharVirtualMemoryFactory(IDateTimeService dateTimeService) : ICharVirtualMemoryFactory
+{
+    public IVirtualMemory<string> Create(string fileName, int size, int fixedStringLength)
+    {
+        var charPageBuffer = CreatePageBuffer(fileName, size, fixedStringLength);
+        return new CharVirtualMemory(charPageBuffer, fixedStringLength, size);
+    }
+
+    private IPageBuffer CreatePageBuffer(string fileName, int size, int fixedStringLength)
+    {
+        var swapfile = new SwapFile(fileName, fixedStringLength * size / sizeof(int));
+        return new PageBuffer(swapfile, dateTimeService);
+    }
+}
\ No newline at end of file
diff --git a/Lab1/Data/Service/InMemoryVirtualMemoryService.cs b/Lab1/Data/Service/InMemoryVirtualMemoryService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3177fb2807ed80484e3d6dcbd7f77011fe092e86
--- /dev/null
+++ b/Lab1/Data/Service/InMemoryVirtualMemoryService.cs
@@ -0,0 +1,70 @@
+using Domain;
+using Domain.Exception;
+using Lab1.Domain.Service;
+using VM.Domain;
+
+namespace Lab1.Data.Service;
+
+public class InMemoryVirtualMemoryService(
+    IIntVirtualMemoryFactory intVirtualMemoryFactory,
+    ICharVirtualMemoryFactory charVirtualMemoryFactory,
+    IVarcharVirtualMemoryFactory varcharVirtualMemoryFactory
+) : IVirtualMemoryService
+{
+    private IVirtualMemory? _virtualMemory;
+    private ArrayType? _arrayType;
+
+    public ArrayType? ActiveArrayType => _arrayType;
+    public bool IsActive => _virtualMemory != null;
+
+    public void CreateCharVirtualMemory(string fileName, int size, int fixedStringLength)
+    {
+        if (_arrayType != null) throw new VirtualMemoryAlreadyInitializedException();
+        _arrayType = ArrayType.Char;
+        _virtualMemory = charVirtualMemoryFactory.Create(fileName, size, fixedStringLength);
+    }
+
+    public void CreateVarcharVirtualMemory(string fileName, int size, int maxStringLength)
+    {
+        if (_arrayType != null) throw new VirtualMemoryAlreadyInitializedException();
+        _arrayType = ArrayType.Varchar;
+        _virtualMemory = varcharVirtualMemoryFactory.Create(fileName, size, maxStringLength);
+    }
+
+    public void CreateIntVirtualMemory(string fileName, int size)
+    {
+        if (_arrayType != null) throw new VirtualMemoryAlreadyInitializedException();
+        _arrayType = ArrayType.Int;
+        _virtualMemory = intVirtualMemoryFactory.Create(fileName, size);
+    }
+
+    public string GetItemByIndex(int index)
+    {
+        var memory = RequireVirtualMemory();
+        var value = memory.Get(index);
+        return value.ToString();
+    }
+
+    public void CloseVirtualMemory()
+    {
+        RequireVirtualMemory().Dispose();
+        _virtualMemory = null;
+        _arrayType = null;
+    }
+
+    public void InsertValueToActiveVirtualMemory(int index, int value)
+    {
+        RequireVirtualMemory().Set(index, value);
+    }
+
+    public void InsertValueToActiveVirtualMemory(int index, string value)
+    {
+        RequireVirtualMemory().Set(index, value);
+    }
+
+    private IVirtualMemory RequireVirtualMemory()
+    {
+        if (_virtualMemory == null) throw new VirtualMemoryNotInitializedException();
+        return _virtualMemory;
+    }
+}
\ No newline at end of file
diff --git a/Lab1/Data/Service/IntVirtualMemoryFactory.cs b/Lab1/Data/Service/IntVirtualMemoryFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9c564d61a4642be775a5bf2fe3fc4233597e38df
--- /dev/null
+++ b/Lab1/Data/Service/IntVirtualMemoryFactory.cs
@@ -0,0 +1,20 @@
+using Lab1.Domain.Service;
+using VM.Domain;
+
+namespace Lab1.Data.Service;
+
+public class IntVirtualMemoryFactory(IDateTimeService dateTimeService) : IIntVirtualMemoryFactory
+{
+    public IVirtualMemory<int> Create(string fileName, int size)
+    {
+        var pageBuffer = CreatePageBuffer(fileName, size);
+        return new IntVirtualMemory(pageBuffer, size);
+    }
+
+
+    private IPageBuffer CreatePageBuffer(string fileName, int size)
+    {
+        var swapfile = new SwapFile(fileName, size);
+        return new PageBuffer(swapfile, dateTimeService);
+    }
+}
\ No newline at end of file
diff --git a/Lab1/Data/Service/VarcharVirtualMemoryFactory.cs b/Lab1/Data/Service/VarcharVirtualMemoryFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..499c09d0ce63522779100c7c3c2d60872b16fd84
--- /dev/null
+++ b/Lab1/Data/Service/VarcharVirtualMemoryFactory.cs
@@ -0,0 +1,13 @@
+using Lab1.Domain.Service;
+using VM.Domain;
+
+namespace Lab1.Data.Service;
+
+public class VarcharVirtualMemoryFactory : IVarcharVirtualMemoryFactory
+{
+    public IVirtualMemory<string> Create(string fileName, int size, int maxStringLength)
+    {
+        var swapFile = new SwapFile(fileName, size);
+        return new VarcharVirtualMemory(swapFile, $"{fileName}.data", maxStringLength, size);
+    }
+}
\ No newline at end of file
diff --git a/Lab1/Data/UseCase/VmCreateCharVirtualMemoryUseCase.cs b/Lab1/Data/UseCase/VmCreateCharVirtualMemoryUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c026f4d434cedbc463c07bddc7504aa3f623a3fd
--- /dev/null
+++ b/Lab1/Data/UseCase/VmCreateCharVirtualMemoryUseCase.cs
@@ -0,0 +1,13 @@
+using Domain.UseCase;
+using Lab1.Domain.Service;
+
+namespace Lab1.Data.UseCase;
+
+public class VmCreateCharVirtualMemoryUseCase(IVirtualMemoryService virtualMemoryService)
+    : ICreateCharVirtualMemoryUseCase
+{
+    public void Invoke(string fileName, int size, int fixedStringLength)
+    {
+        virtualMemoryService.CreateCharVirtualMemory(fileName, size, fixedStringLength);
+    }
+}
\ No newline at end of file
diff --git a/Lab1/Data/UseCase/VmCreateIntVirtualMemoryUseCase.cs b/Lab1/Data/UseCase/VmCreateIntVirtualMemoryUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2e72fbf7aa1de747eec64b155f408b6b7ad60faa
--- /dev/null
+++ b/Lab1/Data/UseCase/VmCreateIntVirtualMemoryUseCase.cs
@@ -0,0 +1,13 @@
+using Domain.UseCase;
+using Lab1.Domain.Service;
+
+namespace Lab1.Data.UseCase;
+
+public class VmCreateIntVirtualMemoryUseCase(IVirtualMemoryService virtualMemoryService)
+    : ICreateIntVirtualMemoryUseCase
+{
+    public void Invoke(string fileName, int size)
+    {
+        virtualMemoryService.CreateIntVirtualMemory(fileName, size);
+    }
+}
\ No newline at end of file
diff --git a/Lab1/Data/UseCase/VmCreateVarcharVirtualMemoryUseCase.cs b/Lab1/Data/UseCase/VmCreateVarcharVirtualMemoryUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..af494510b7a31e32fd6bce05c2ce40e37860e3fc
--- /dev/null
+++ b/Lab1/Data/UseCase/VmCreateVarcharVirtualMemoryUseCase.cs
@@ -0,0 +1,13 @@
+using Domain.UseCase;
+using Lab1.Domain.Service;
+
+namespace Lab1.Data.UseCase;
+
+public class VmCreateVarcharVirtualMemoryUseCase(IVirtualMemoryService virtualMemoryService)
+    : ICreateVarcharVirtualMemoryUseCase
+{
+    public void Invoke(string fileName, int size, int maxStringLength)
+    {
+        virtualMemoryService.CreateVarcharVirtualMemory(fileName, size, maxStringLength);
+    }
+}
\ No newline at end of file
diff --git a/Lab1/Data/UseCase/VmExitUseCase.cs b/Lab1/Data/UseCase/VmExitUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7beee7839764b5d5dff59cc5911a18851fb8cda6
--- /dev/null
+++ b/Lab1/Data/UseCase/VmExitUseCase.cs
@@ -0,0 +1,12 @@
+using Domain.UseCase;
+using Lab1.Domain.Service;
+
+namespace Lab1.Data.UseCase;
+
+public class VmExitUseCase(IVirtualMemoryService virtualMemoryService) : IExitUseCase
+{
+    public void Invoke()
+    {
+        virtualMemoryService.CloseVirtualMemory();
+    }
+}
\ No newline at end of file
diff --git a/Lab1/Data/UseCase/VmGetActiveArrayTypeUseCase.cs b/Lab1/Data/UseCase/VmGetActiveArrayTypeUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2cf73c910d89f99cecbba121c45c9521779dbb2d
--- /dev/null
+++ b/Lab1/Data/UseCase/VmGetActiveArrayTypeUseCase.cs
@@ -0,0 +1,13 @@
+using Domain;
+using Domain.UseCase;
+using Lab1.Domain.Service;
+
+namespace Lab1.Data.UseCase;
+
+public class VmGetActiveArrayTypeUseCase(IVirtualMemoryService virtualMemoryService) : IGetActiveArrayTypeUseCase
+{
+    public ArrayType? Invoke()
+    {
+        return virtualMemoryService.ActiveArrayType;
+    }
+}
\ No newline at end of file
diff --git a/Lab1/Data/UseCase/VmGetItemByIndexUseCase.cs b/Lab1/Data/UseCase/VmGetItemByIndexUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e50a445b3c196b862c436e8311d8beb1066c8553
--- /dev/null
+++ b/Lab1/Data/UseCase/VmGetItemByIndexUseCase.cs
@@ -0,0 +1,12 @@
+using Domain.UseCase;
+using Lab1.Domain.Service;
+
+namespace Lab1.Data.UseCase;
+
+public class VmGetItemByIndexUseCase(IVirtualMemoryService virtualMemoryService) : IGetItemByIndexUseCase
+{
+    public string Invoke(int index)
+    {
+        return virtualMemoryService.GetItemByIndex(index);
+    }
+}
\ No newline at end of file
diff --git a/Lab1/Data/UseCase/VmInputUseCase.cs b/Lab1/Data/UseCase/VmInputUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..550b41f94f6a3f266d72145232ec2a03acb4d7aa
--- /dev/null
+++ b/Lab1/Data/UseCase/VmInputUseCase.cs
@@ -0,0 +1,12 @@
+using Domain.UseCase;
+using Lab1.Domain.Service;
+
+namespace Lab1.Data.UseCase;
+
+public class VmInputStringUseCase(IVirtualMemoryService virtualMemoryService) : IInputStringUseCase
+{
+    public void Invoke(int index, string value)
+    {
+        virtualMemoryService.InsertValueToActiveVirtualMemory(index, value);
+    }
+}
\ No newline at end of file
diff --git a/Lab1/Data/UseCase/VmIntInputUseCase.cs b/Lab1/Data/UseCase/VmIntInputUseCase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f4e26a591b00ce489386a1b8e54f2101880a0247
--- /dev/null
+++ b/Lab1/Data/UseCase/VmIntInputUseCase.cs
@@ -0,0 +1,12 @@
+using Domain.UseCase;
+using Lab1.Domain.Service;
+
+namespace Lab1.Data.UseCase;
+
+public class VmInputIntUseCase(IVirtualMemoryService virtualMemoryService) : IInputIntUseCase
+{
+    public void Invoke(int index, int value)
+    {
+        virtualMemoryService.InsertValueToActiveVirtualMemory(index, value);
+    }
+}
\ No newline at end of file
diff --git a/Lab1/Domain/Service/ICharVirtualMemoryFactory.cs b/Lab1/Domain/Service/ICharVirtualMemoryFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bcdbbf8f399dea2a46f3c77408b438d174d51d3b
--- /dev/null
+++ b/Lab1/Domain/Service/ICharVirtualMemoryFactory.cs
@@ -0,0 +1,8 @@
+using VM.Domain;
+
+namespace Lab1.Domain.Service;
+
+public interface ICharVirtualMemoryFactory
+{
+    IVirtualMemory<string> Create(string fileName, int size, int fixedStringLength);
+}
\ No newline at end of file
diff --git a/Lab1/Domain/Service/IIntVirtualMemoryFactory.cs b/Lab1/Domain/Service/IIntVirtualMemoryFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5dfd6c321173bdf23145ad90dc833cd0120919d3
--- /dev/null
+++ b/Lab1/Domain/Service/IIntVirtualMemoryFactory.cs
@@ -0,0 +1,8 @@
+using VM.Domain;
+
+namespace Lab1.Domain.Service;
+
+public interface IIntVirtualMemoryFactory
+{
+    IVirtualMemory<int> Create(string fileName, int size);
+}
\ No newline at end of file
diff --git a/Lab1/Domain/Service/IVarcharVirtualMemoryFactory.cs b/Lab1/Domain/Service/IVarcharVirtualMemoryFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c1ec72f959bf17e41f465618b04228bfc5594b5f
--- /dev/null
+++ b/Lab1/Domain/Service/IVarcharVirtualMemoryFactory.cs
@@ -0,0 +1,8 @@
+using VM.Domain;
+
+namespace Lab1.Domain.Service;
+
+public interface IVarcharVirtualMemoryFactory
+{
+    IVirtualMemory<string> Create(string fileName, int size, int maxStringLength);
+}
\ No newline at end of file
diff --git a/Lab1/Domain/Service/IVirtualMemoryService.cs b/Lab1/Domain/Service/IVirtualMemoryService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0e9f7d7431e37fd0176f09b8ddfee1cfbd451b85
--- /dev/null
+++ b/Lab1/Domain/Service/IVirtualMemoryService.cs
@@ -0,0 +1,24 @@
+using Domain;
+
+namespace Lab1.Domain.Service;
+
+public interface IVirtualMemoryService
+{
+    public ArrayType? ActiveArrayType { get; }
+    
+    public bool IsActive { get; }
+    
+    void CreateCharVirtualMemory(string fileName, int size, int fixedStringLength);
+
+    void CreateVarcharVirtualMemory(string fileName, int size, int maxStringLength);
+
+    void CreateIntVirtualMemory(string fileName, int size);
+
+    string GetItemByIndex(int index);
+
+    void CloseVirtualMemory();
+
+    void InsertValueToActiveVirtualMemory(int index, int value);
+    
+    void InsertValueToActiveVirtualMemory(int index, string value);
+}
\ No newline at end of file
diff --git a/Lab1/Lab1.csproj b/Lab1/Lab1.csproj
index 85b49591f61b9368cbdc71fc54757d476c41f1d5..c4711cf809bfef49a473c20a0c5431be432e2ace 100644
--- a/Lab1/Lab1.csproj
+++ b/Lab1/Lab1.csproj
@@ -7,4 +7,13 @@
         <Nullable>enable</Nullable>
     </PropertyGroup>
 
+    <ItemGroup>
+        <ProjectReference Include="..\VM\VM.csproj"/>
+        <ProjectReference Include="..\UI\UI.csproj" />
+    </ItemGroup>
+
+    <ItemGroup>
+      <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2" />
+    </ItemGroup>
+
 </Project>
diff --git a/Lab1/Program.cs b/Lab1/Program.cs
index e5dff12bc410be0bac59bc70865a8e21827ec7f3..76d77234e41c370794f626d58b2836c261b583f0 100644
--- a/Lab1/Program.cs
+++ b/Lab1/Program.cs
@@ -1,3 +1,48 @@
-п»ї// See https://aka.ms/new-console-template for more information
+п»їusing Domain.UseCase;
+using Lab1.Data.Service;
+using Lab1.Data.UseCase;
+using Lab1.Domain.Service;
+using Microsoft.Extensions.DependencyInjection;
+using UI.Impl;
+using UI.Model;
+using UI.Presentation;
+using UI.Presentation.Command;
+using VM.Domain;
 
-Console.WriteLine("Hello, World!");
\ No newline at end of file
+var services = new ServiceCollection();
+
+services.AddSingleton<IDateTimeService, SystemDateTimeService>();
+services.AddSingleton<IConsole, SystemConsole>();
+
+services.AddSingleton<IApplicationLifecycle, ApplicationLifecycle>();
+services.AddSingleton<IApplication, App>();
+services.AddSingleton<ICommandProcessor, CommandProcessor>();
+
+services.AddSingleton<CreateCommandExecutor>();
+services.AddSingleton<ExitCommandExecutor>();
+services.AddSingleton<InputCommandExecutor>();
+services.AddSingleton<PrintCommandExecutor>();
+
+services.AddTransient<ICommand, CreateCommand>();
+services.AddTransient<ICommand, ExitCommand>();
+services.AddTransient<ICommand, InputCommand>();
+services.AddTransient<ICommand, PrintCommand>();
+
+services.AddSingleton<IVirtualMemoryService, InMemoryVirtualMemoryService>();
+services.AddSingleton<ICharVirtualMemoryFactory, CharVirtualMemoryFactory>();
+services.AddSingleton<IIntVirtualMemoryFactory, IntVirtualMemoryFactory>();
+services.AddSingleton<IVarcharVirtualMemoryFactory, VarcharVirtualMemoryFactory>();
+
+services.AddSingleton<IExitUseCase, VmExitUseCase>();
+services.AddSingleton<IGetItemByIndexUseCase, VmGetItemByIndexUseCase>();
+services.AddSingleton<IInputIntUseCase, VmInputIntUseCase>();
+services.AddSingleton<IInputStringUseCase, VmInputStringUseCase>();
+services.AddSingleton<ICreateCharVirtualMemoryUseCase, VmCreateCharVirtualMemoryUseCase>();
+services.AddSingleton<ICreateIntVirtualMemoryUseCase, VmCreateIntVirtualMemoryUseCase>();
+services.AddSingleton<ICreateVarcharVirtualMemoryUseCase, VmCreateVarcharVirtualMemoryUseCase>();
+services.AddSingleton<IGetActiveArrayTypeUseCase, VmGetActiveArrayTypeUseCase>();
+
+var serviceProvider = services.BuildServiceProvider();
+
+var application = serviceProvider.GetRequiredService<IApplication>();
+application.Run();
\ No newline at end of file
diff --git a/UI.Tests/Impl/ExitCommandExecutorTest.cs b/UI.Tests/Impl/ExitCommandExecutorTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bc45c0599b1cd9e7b79d9d73027b3a88b9a81dcf
--- /dev/null
+++ b/UI.Tests/Impl/ExitCommandExecutorTest.cs
@@ -0,0 +1,55 @@
+using System;
+using Domain.UseCase;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using UI.Impl;
+using UI.Presentation;
+
+namespace UI.Tests.Impl
+{
+    [TestClass]
+    public class ExitCommandExecutorTests
+    {
+        [TestMethod]
+        public void OnCommand_ValidCommand_CallsUseCaseInvoke()
+        {
+            var mockApplication = new Mock<IApplicationLifecycle>();
+            var mockConsole = new Mock<IConsole>();
+            var mockUseCase = new Mock<IExitUseCase>();
+            var executor = new ExitCommandExecutor(mockUseCase.Object, mockApplication.Object, mockConsole.Object);
+            var args = new[] { "exit" };
+
+            executor.OnCommand("exit", args);
+
+            mockUseCase.Verify(u => u.Invoke(), Times.Once);
+        }
+
+        [TestMethod]
+        public void OnCommand_EmptyArguments_CallsUseCaseInvoke()
+        {
+            var mockApplication = new Mock<IApplicationLifecycle>();
+            var mockUseCase = new Mock<IExitUseCase>();
+            var mockConsole = new Mock<IConsole>();
+            var executor = new ExitCommandExecutor(mockUseCase.Object, mockApplication.Object, mockConsole.Object);
+            var args = Array.Empty<string>();
+
+            executor.OnCommand("exit", args);
+
+            mockUseCase.Verify(u => u.Invoke(), Times.Once);
+        }
+
+        [TestMethod]
+        public void OnCommand_NullArguments_CallsUseCaseInvoke()
+        {
+            var mockApplication = new Mock<IApplicationLifecycle>();
+            var mockUseCase = new Mock<IExitUseCase>();
+            var mockConsole = new Mock<IConsole>();
+            var executor = new ExitCommandExecutor(mockUseCase.Object, mockApplication.Object, mockConsole.Object);
+            string[] args = null;
+
+            executor.OnCommand("exit", args);
+
+            mockUseCase.Verify(u => u.Invoke(), Times.Once);
+        }
+    }
+}
\ No newline at end of file
diff --git a/UI.Tests/Model/CommandTest.cs b/UI.Tests/Model/CommandTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5b4290ad6df835d11c10ee53c1b282ed2205269f
--- /dev/null
+++ b/UI.Tests/Model/CommandTest.cs
@@ -0,0 +1,98 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using UI.Interface;
+using UI.Model;
+
+namespace UI.Tests.Model
+{
+    [TestClass]
+    public class CommandTests
+    {
+        [TestMethod]
+        public void Constructor_ThrowsException_WhenNameContainsWhitespace()
+        {
+            var mockExecutor = new Mock<ICommandExecutor>();
+            Assert.ThrowsException<ArgumentException>(() => new Command("invalid name", mockExecutor.Object));
+        }
+
+        [TestMethod]
+        public void Constructor_ThrowsException_WhenNameIsEmpty()
+        {
+            var mockExecutor = new Mock<ICommandExecutor>();
+            Assert.ThrowsException<ArgumentException>(() => new Command("", mockExecutor.Object));
+        }
+
+        [TestMethod]
+        public void Execute_CallsOnCommand_WithCorrectArguments()
+        {
+            var mockExecutor = new Mock<ICommandExecutor>();
+            var command = new Command("test", mockExecutor.Object);
+            var args = new[] { "test", "arg1", "arg2" };
+
+            command.Execute(args);
+
+            mockExecutor.Verify(e => e.OnCommand("test", new[] { "arg1", "arg2" }), Times.Once);
+        }
+
+        [TestMethod]
+        public void Execute_DoesNotCallOnCommand_WhenArgsIsNull()
+        {
+            var mockExecutor = new Mock<ICommandExecutor>();
+            var command = new Command("test", mockExecutor.Object);
+            string[] args = null;
+
+            command.Execute(args);
+
+            mockExecutor.Verify(e => e.OnCommand(It.IsAny<string>(), It.IsAny<string[]>()), Times.Never);
+        }
+
+        [TestMethod]
+        public void Execute_DoesNotCallOnCommand_WhenArgsLengthIsZero()
+        {
+            var mockExecutor = new Mock<ICommandExecutor>();
+            var command = new Command("test", mockExecutor.Object);
+            var args = Array.Empty<string>();
+
+            command.Execute(args);
+
+            mockExecutor.Verify(e => e.OnCommand(It.IsAny<string>(), It.IsAny<string[]>()), Times.Never);
+        }
+
+        [TestMethod]
+        public void Execute_DoesNotCallOnCommand_WhenFirstArgDoesNotMatchCommandName()
+        {
+            var mockExecutor = new Mock<ICommandExecutor>();
+            var command = new Command("test", mockExecutor.Object);
+            var args = new[] { "other", "arg1" };
+
+            command.Execute(args);
+
+            mockExecutor.Verify(e => e.OnCommand(It.IsAny<string>(), It.IsAny<string[]>()), Times.Never);
+        }
+
+        [TestMethod]
+        public void Execute_CallsOnCommand_WithEmptyStringArguments()
+        {
+            var mockExecutor = new Mock<ICommandExecutor>();
+            var command = new Command("test", mockExecutor.Object);
+            var args = new[] { "test", "" };
+
+            command.Execute(args);
+
+            mockExecutor.Verify(e => e.OnCommand("test", new[] { "" }), Times.Once);
+        }
+
+        [TestMethod]
+        public void Execute_CallsOnCommand_WithMultipleArguments()
+        {
+            var mockExecutor = new Mock<ICommandExecutor>();
+            var command = new Command("test", mockExecutor.Object);
+            var args = new[] { "test", "arg1", "arg2", "arg3" };
+
+            command.Execute(args);
+
+            mockExecutor.Verify(e => e.OnCommand("test", new[] { "arg1", "arg2", "arg3" }), Times.Once);
+        }
+    }
+}
diff --git a/UI.Tests/Presentation/AppTest.cs b/UI.Tests/Presentation/AppTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f34e937a3c4a45419e89bae1bbb934338cb34db8
--- /dev/null
+++ b/UI.Tests/Presentation/AppTest.cs
@@ -0,0 +1,54 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using UI.Presentation;
+
+namespace UI.Tests.Presentation
+{
+    [TestClass]
+    public class AppTests
+    {
+        private Mock<IApplicationLifecycle> _mockLifecycle;
+        private Mock<ICommandProcessor> _mockCommandProcessor;
+        private Mock<IConsole> _mockConsole;
+
+        private App _app;
+
+        [TestInitialize]
+        public void Setup()
+        {
+            _mockLifecycle = new Mock<IApplicationLifecycle>();
+            _mockCommandProcessor = new Mock<ICommandProcessor>();
+            _mockConsole = new Mock<IConsole>();
+            _app = new App(_mockLifecycle.Object, _mockCommandProcessor.Object, _mockConsole.Object);
+        }
+
+        [TestMethod]
+        public void LifecycleProperty_ReturnsInjectedLifecycle()
+        {
+            Assert.AreEqual(_mockLifecycle.Object, _app.Lifecycle);
+        }
+
+        [TestMethod]
+        public void Run_CallsProcessCommands_WhileIsRunningIsTrue()
+        {
+            _mockLifecycle.SetupSequence(l => l.IsRunning)
+                .Returns(true)
+                .Returns(true)
+                .Returns(false); // Остановка после двух вызовов
+
+            _app.Run();
+
+            _mockCommandProcessor.Verify(p => p.ProcessCommands(), Times.Exactly(2));
+        }
+
+        [TestMethod]
+        public void Run_DoesNotCallProcessCommands_WhenIsRunningIsFalse()
+        {
+            _mockLifecycle.Setup(l => l.IsRunning).Returns(false);
+
+            _app.Run();
+
+            _mockCommandProcessor.Verify(p => p.ProcessCommands(), Times.Never);
+        }
+    }
+}
\ No newline at end of file
diff --git a/UI.Tests/Presentation/ApplicationLifecycleTest.cs b/UI.Tests/Presentation/ApplicationLifecycleTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f9507cc5cca4b502372f5ccaafaba867ebc4f978
--- /dev/null
+++ b/UI.Tests/Presentation/ApplicationLifecycleTest.cs
@@ -0,0 +1,31 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using UI.Presentation;
+
+namespace UI.Tests.Presentation
+{
+    [TestClass]
+    public class ApplicationLifecycleTests
+    {
+        private ApplicationLifecycle _lifecycle;
+
+        [TestInitialize]
+        public void Setup()
+        {
+            _lifecycle = new ApplicationLifecycle();
+        }
+
+        [TestMethod]
+        public void IsRunning_ShouldBeTrue_ByDefault()
+        {
+            Assert.IsTrue(_lifecycle.IsRunning);
+        }
+
+        [TestMethod]
+        public void Finish_ShouldSetIsRunning_ToFalse()
+        {
+            _lifecycle.Finish();
+
+            Assert.IsFalse(_lifecycle.IsRunning);
+        }
+    }
+}
\ No newline at end of file
diff --git a/UI.Tests/Presentation/CommandProcessorTest.cs b/UI.Tests/Presentation/CommandProcessorTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8671d9b71bc3153bf3b5f09a480659d910da57e8
--- /dev/null
+++ b/UI.Tests/Presentation/CommandProcessorTest.cs
@@ -0,0 +1,44 @@
+using System.Collections.Generic;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using UI.Model;
+using UI.Presentation;
+
+namespace UI.Tests.Presentation
+{
+    [TestClass]
+    public class CommandProcessorTests
+    {
+        private Mock<ICommand> _mockCommand1;
+        private Mock<ICommand> _mockCommand2;
+        private Mock<IConsole> _mockConsole;
+
+        [TestInitialize]
+        public void Setup()
+        {
+            _mockCommand1 = new Mock<ICommand>();
+            _mockCommand2 = new Mock<ICommand>();
+            _mockConsole = new Mock<IConsole>();
+        }
+
+        [TestMethod]
+        public void ProcessCommands_ShouldExecuteCommands_WhenInputIsValid()
+        {
+            // Arrange
+            var commands = new List<ICommand> { _mockCommand1.Object, _mockCommand2.Object };
+            var processor = new CommandProcessor(commands, _mockConsole.Object);
+            var input = "command1 arg1 arg2";
+
+            // Set up the mock to return the input string
+            _mockConsole.Setup(c => c.ReadLine()).Returns(input);
+
+            // Act
+            processor.ProcessCommands();
+
+            // Assert
+            // command1 should be executed with ["command1", "arg1", "arg2"]
+            _mockCommand1.Verify(c => c.Execute(new[] { "command1", "arg1", "arg2" }), Times.Once);
+            _mockCommand2.Verify(c => c.Execute(new[] { "command1", "arg1", "arg2" }), Times.Once);
+        }
+    }
+}
diff --git a/UI.Tests/Presentation/SystemConsoleTest.cs b/UI.Tests/Presentation/SystemConsoleTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ffb5f209a1049d989e5719ceed3e9c44a461018d
--- /dev/null
+++ b/UI.Tests/Presentation/SystemConsoleTest.cs
@@ -0,0 +1,102 @@
+using System;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using UI.Presentation;
+
+namespace UI.Tests.Presentation
+{
+    [TestClass]
+    public class SystemConsoleTests
+    {
+        private StringWriter _stringWriter;
+        private StringReader _stringReader;
+        private TextWriter _originalOutput;
+        private TextReader _originalInput;
+
+        [TestInitialize]
+        public void Setup()
+        {
+            // Backup original streams
+            _originalOutput = Console.Out;
+            _originalInput = Console.In;
+
+            // Set up StringWriter to capture Console output
+            _stringWriter = new StringWriter();
+            Console.SetOut(_stringWriter);
+
+            // Set up StringReader for simulating Console input
+            _stringReader = new StringReader("Test Input");
+            Console.SetIn(_stringReader);
+        }
+
+        [TestCleanup]
+        public void Cleanup()
+        {
+            // Restore original streams
+            Console.SetOut(_originalOutput);
+            Console.SetIn(_originalInput);
+
+            _stringWriter?.Dispose();
+            _stringReader?.Dispose();
+        }
+
+        [TestMethod]
+        public void WriteLine_ShouldCallConsoleWriteLine_WithCorrectMessage()
+        {
+            // Arrange
+            var console = new SystemConsole();
+            var message = "Hello, World!";
+
+            // Act
+            console.WriteLine(message);
+
+            // Assert
+            var output = _stringWriter.ToString();
+            Assert.AreEqual(message + Environment.NewLine, output);
+        }
+
+        [TestMethod]
+        public void ReadLine_ShouldReturnInput_WhenNotNull()
+        {
+            // Arrange
+            var console = new SystemConsole();
+            var expectedInput = "Test Input";
+
+            // Act
+            var result = console.ReadLine();
+
+            // Assert
+            Assert.AreEqual(expectedInput, result);
+        }
+
+        [TestMethod]
+        public void ReadLine_ShouldReturnEmptyString_WhenInputIsNull()
+        {
+            // Arrange
+            var console = new SystemConsole();
+            Console.SetIn(new StringReader("")); // Simulating null input
+
+            Console.In.ReadLine();
+            // Act
+            var result = console.ReadLine();
+
+            // Assert
+            Assert.AreEqual(string.Empty, result);
+        }
+
+        [TestMethod]
+        public void Write_ShouldCallConsoleWrite_WithCorrectMessage()
+        {
+            // Arrange
+            var console = new SystemConsole();
+            var message = "Test message";
+
+            // Act
+            console.Write(message);
+
+            // Assert
+            var output = _stringWriter.ToString();
+            Assert.AreEqual(message, output);
+        }
+    }
+}
diff --git a/UI.Tests/UI.Tests.csproj b/UI.Tests/UI.Tests.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..d7bbbe1fb26da4135707cffd0f74cae42e7de5ae
--- /dev/null
+++ b/UI.Tests/UI.Tests.csproj
@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFrameworks>net9.0</TargetFrameworks>
+    
+    <IsPackable>false</IsPackable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="JetBrains.Annotations" Version="2025.1.0-eap1" />
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
+    <PackageReference Include="Moq" Version="4.20.72" />
+    <PackageReference Include="MSTest.TestAdapter" Version="3.8.2" />
+    <PackageReference Include="MSTest.TestFramework" Version="3.8.2" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\UI\UI.csproj" />
+  </ItemGroup>
+  
+</Project>
\ No newline at end of file
diff --git a/UI/Impl/CreateCommandExecutor.cs b/UI/Impl/CreateCommandExecutor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..92f39db9df169065d43609ee56ece9a704d80aac
--- /dev/null
+++ b/UI/Impl/CreateCommandExecutor.cs
@@ -0,0 +1,130 @@
+using Domain;
+using Domain.Exception;
+using Domain.UseCase;
+using UI.Interface;
+using UI.Presentation;
+
+namespace UI.Impl;
+
+public class CreateCommandExecutor(
+    ICreateIntVirtualMemoryUseCase createIntVirtualMemoryUseCase,
+    ICreateCharVirtualMemoryUseCase createCharVirtualMemoryUseCase,
+    ICreateVarcharVirtualMemoryUseCase createVarcharVirtualMemoryUseCase,
+    IConsole console
+) : ICommandExecutor
+{
+    public void OnCommand(string command, string[] args)
+    {
+        if (args.Length < 3)
+        {
+            PrintUsage();
+            return;
+        }
+        var fileName = args[0];
+        var resultArrayType = ParseArrayType(args[1], out var arrayType);
+        if (!resultArrayType)
+        {
+            PrintUsage(StringResource.InvalidArrayType);
+            return;
+        }
+        
+        var resultSize = int.TryParse(args[2], out var size);
+        if (!resultSize)
+        {
+            PrintUsage(StringResource.InvalidSize);
+            return;
+        }
+        switch (arrayType)
+        {
+            case ArrayType.Int:
+                try
+                {
+                    createIntVirtualMemoryUseCase.Invoke(fileName, size);
+                }
+                catch (VirtualMemoryAlreadyInitializedException)
+                {
+                    PrintUsage(StringResource.VirtualMemoryInitialized);
+                    return;
+                }
+                break;
+            case ArrayType.Char:
+                if (args.Length < 4)
+                {
+                    PrintUsage(StringResource.CharTypeRequiresStringLength);
+                    return;
+                }
+                
+                if (!int.TryParse(args[3], out var fixedStringLength))
+                {
+                    PrintUsage(StringResource.InvalidStringLength);
+                    return;
+                }
+
+                try
+                {
+                    createCharVirtualMemoryUseCase.Invoke(fileName, size, fixedStringLength);
+                }
+                catch (VirtualMemoryAlreadyInitializedException)
+                {
+                    PrintUsage(StringResource.VirtualMemoryInitialized);
+                    return;
+                }
+
+                break;
+            case ArrayType.Varchar:
+                if (args.Length < 4)
+                {
+                    PrintUsage(StringResource.VarcharTypeRequiresMaxStringLength);
+                    return;
+                }
+                if (!int.TryParse(args[3], out var maxStringLength))
+                {
+                    PrintUsage(StringResource.InvalidStringLength);
+                    return;
+                }
+                try
+                {
+                    createVarcharVirtualMemoryUseCase.Invoke(fileName, size, maxStringLength);
+                }
+                catch (VirtualMemoryAlreadyInitializedException)
+                {
+                    PrintUsage(StringResource.VirtualMemoryInitialized);
+                    return;
+                }
+
+                break;
+            default:
+                throw new ArgumentOutOfRangeException();
+        }
+
+        console.WriteLine(StringResource.ArrayCreated);
+    }
+
+    private void PrintUsage(string prefix = "")
+    {
+        if (prefix.Length != 0)
+        {
+            console.Write(prefix + " ");
+        }
+        console.WriteLine($"{StringResource.CommandsUsage.Create}");
+    }
+    
+    private bool ParseArrayType(string input, out ArrayType result)
+    {
+        switch (input.ToLower())
+        {
+            case ArrayTypeTranscript.Int:
+                result = ArrayType.Int;
+                return true;
+            case ArrayTypeTranscript.Char:
+                result = ArrayType.Char;
+                return true;
+            case ArrayTypeTranscript.Varchar:
+                result = ArrayType.Varchar;
+                return true;
+            default:
+                result = ArrayType.Int;
+                return false;
+        }
+    }
+}
\ No newline at end of file
diff --git a/UI/Impl/ExitCommandExecutor.cs b/UI/Impl/ExitCommandExecutor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fe19f9344d0835950084ee07fb6852ad29c2bdbe
--- /dev/null
+++ b/UI/Impl/ExitCommandExecutor.cs
@@ -0,0 +1,31 @@
+using Domain.Exception;
+using Domain.UseCase;
+using UI.Interface;
+using UI.Presentation;
+
+namespace UI.Impl;
+
+public class ExitCommandExecutor(IExitUseCase useCase, IApplicationLifecycle applicationLifecycle, IConsole console): ICommandExecutor
+{
+    public void OnCommand(string command, string[] args)
+    {
+        applicationLifecycle.Finish();
+        try
+        {
+            useCase.Invoke();
+        }
+        catch (VirtualMemoryNotInitializedException)
+        {
+            console.WriteLine(StringResource.Exit);
+        }
+    }
+
+    private void PrintUsage(string prefix = "")
+    {
+        if (prefix.Length != 0)
+        {
+            console.Write(prefix + " ");
+        }
+        console.WriteLine(StringResource.CommandsUsage.Exit);
+    }
+}
\ No newline at end of file
diff --git a/UI/Impl/InputCommandExecutor.cs b/UI/Impl/InputCommandExecutor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..64da3d46995516330bf03f5d4f1faa11458b4247
--- /dev/null
+++ b/UI/Impl/InputCommandExecutor.cs
@@ -0,0 +1,92 @@
+using Domain;
+using Domain.Exception;
+using Domain.UseCase;
+using UI.Interface;
+using UI.Presentation;
+
+namespace UI.Impl;
+
+public class InputCommandExecutor(
+    IInputIntUseCase inputIntUseCase,
+    IInputStringUseCase inputStringUseCase,
+    IGetActiveArrayTypeUseCase getActiveArrayTypeUseCase,
+    IConsole console
+) : ICommandExecutor
+{
+    public void OnCommand(string command, string[] args)
+    {
+        if (args.Length < 2)
+        {
+            PrintUsage();
+            return;
+        }
+        if (!int.TryParse(args[0], out var index))
+        {
+            PrintUsage(StringResource.InvalidIndex);
+            return;
+        }
+        var value = args[1];
+        var activeArrayType = getActiveArrayTypeUseCase.Invoke();
+        switch (activeArrayType)
+        {
+            case ArrayType.Int:
+                try
+                {
+                    if (!int.TryParse(value, out var intValue))
+                    {
+                        PrintUsage(StringResource.InvalidValue);
+                        return;
+                    }
+                    inputIntUseCase.Invoke(index, intValue);
+                    break;
+                }
+                catch (VirtualMemoryNotInitializedException)
+                {
+                    PrintUsage(StringResource.VirtualMemoryNotInitialized);
+                    return;
+                }
+                catch (IndexOutOfRangeException)
+                {
+                    PrintUsage(StringResource.IndexOutOfRange);
+                    return;
+                }
+            case ArrayType.Char:
+            case ArrayType.Varchar:
+                try
+                {
+                    inputStringUseCase.Invoke(index, value);
+                    break;
+                }
+                catch (VirtualMemoryNotInitializedException)
+                {
+                    PrintUsage(StringResource.VirtualMemoryNotInitialized);
+                    return;
+                }
+                catch (IndexOutOfRangeException)
+                {
+                    PrintUsage(StringResource.IndexOutOfRange);
+                    return;
+                }
+                catch (ArgumentException)
+                {
+                    PrintUsage(StringResource.StringLengthOutOfLimit);
+                    return;
+                }
+            case null:
+                PrintUsage(StringResource.VirtualMemoryNotInitialized);
+                break;
+            default:
+                throw new ArgumentOutOfRangeException();
+        }
+        console.WriteLine(StringResource.InputSuccess);
+    }
+
+    private void PrintUsage(string prefix = "")
+    {
+        if (prefix.Length != 0)
+        {
+            console.Write(prefix + " ");
+        }
+        console.WriteLine(StringResource.CommandsUsage.Input);
+    }
+}
\ No newline at end of file
diff --git a/UI/Impl/PrintCommandExecutor.cs b/UI/Impl/PrintCommandExecutor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..34726a4254ed0398219bfddf1250ca5643a86565
--- /dev/null
+++ b/UI/Impl/PrintCommandExecutor.cs
@@ -0,0 +1,46 @@
+using Domain.Exception;
+using Domain.UseCase;
+using UI.Interface;
+using UI.Presentation;
+
+namespace UI.Impl;
+
+public class PrintCommandExecutor(IGetItemByIndexUseCase useCase, IConsole console) : ICommandExecutor
+{
+    public void OnCommand(string command, string[] args)
+    {
+        if (args.Length < 1)
+        {
+            PrintUsage();
+            return;
+        }
+        if (!int.TryParse(args[0], out var index))
+        {
+            PrintUsage(StringResource.InvalidIndex);
+            return;
+        }
+
+        try
+        {
+            var value = useCase.Invoke(index);
+            console.WriteLine(value);
+        }
+        catch (VirtualMemoryNotInitializedException)
+        {
+            PrintUsage(StringResource.VirtualMemoryNotInitialized);
+        }
+        catch (InvalidOperationException)
+        {
+            PrintUsage(StringResource.ElementNotInitialized);
+        }
+    }
+
+    private void PrintUsage(string prefix = "")
+    {
+        if (prefix.Length != 0)
+        {
+            console.Write(prefix + " ");
+        }
+        console.WriteLine(StringResource.CommandsUsage.Print);
+    }
+}
\ No newline at end of file
diff --git a/UI/Interface/ICommandExecutor.cs b/UI/Interface/ICommandExecutor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d1f9063ed093d2416ac42197c25be186a2515144
--- /dev/null
+++ b/UI/Interface/ICommandExecutor.cs
@@ -0,0 +1,6 @@
+namespace UI.Interface;
+
+public interface ICommandExecutor
+{
+    void OnCommand(string command, string[] args);
+}
\ No newline at end of file
diff --git a/UI/Model/Command.cs b/UI/Model/Command.cs
new file mode 100644
index 0000000000000000000000000000000000000000..20167bd59bae03d471045aed2d61742ef0a8f489
--- /dev/null
+++ b/UI/Model/Command.cs
@@ -0,0 +1,39 @@
+using UI.Interface;
+
+namespace UI.Model;
+
+public class Command : ICommand
+{
+    public Command(string name, ICommandExecutor commandExecutor)
+    {
+        _commandExecutor = commandExecutor;
+        Name = name;
+    }
+
+    private readonly ICommandExecutor _commandExecutor;
+
+    private readonly string _name;
+
+    public string Name
+    {
+        get => _name;
+        private init
+        {
+            if (value.Any(char.IsWhiteSpace) || value.Length == 0)
+            {
+                throw new ArgumentException("Command name cannot contain whitespace or be empty");
+            }
+
+            _name = value;
+        }
+    }
+
+    public bool Execute(string[]? args)
+    {
+        if (args == null || args.Length == 0) return false;
+        if (!args[0].Equals(Name)) return false;
+        var argsWithoutCommand = args.Skip(1).ToArray();
+        _commandExecutor.OnCommand(Name, argsWithoutCommand);
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/UI/Model/ICommand.cs b/UI/Model/ICommand.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fc1cd82e459e1b09f35a17918a561b616019c192
--- /dev/null
+++ b/UI/Model/ICommand.cs
@@ -0,0 +1,7 @@
+namespace UI.Model;
+
+public interface ICommand
+{
+    public string Name { get; }
+    public bool Execute(string[]? args);
+}
\ No newline at end of file
diff --git a/UI/Presentation/App.cs b/UI/Presentation/App.cs
new file mode 100644
index 0000000000000000000000000000000000000000..47f172d99dd76caaafa7ead3f41b9b65b4f6cec9
--- /dev/null
+++ b/UI/Presentation/App.cs
@@ -0,0 +1,19 @@
+namespace UI.Presentation;
+
+public class App(
+    IApplicationLifecycle lifecycle,
+    ICommandProcessor commandProcessor,
+    IConsole console
+) : IApplication
+{
+    public IApplicationLifecycle Lifecycle => lifecycle;
+
+    public void Run()
+    {
+        console.WriteLine(StringResource.CommandsUsage.Help);
+        while (Lifecycle.IsRunning)
+        {
+            commandProcessor.ProcessCommands();
+        }
+    }
+}
\ No newline at end of file
diff --git a/UI/Presentation/ApplicationLifecycle.cs b/UI/Presentation/ApplicationLifecycle.cs
new file mode 100644
index 0000000000000000000000000000000000000000..549da9cfeeaa59dc101408b9fb9ed7c559ec81fe
--- /dev/null
+++ b/UI/Presentation/ApplicationLifecycle.cs
@@ -0,0 +1,11 @@
+namespace UI.Presentation;
+
+public class ApplicationLifecycle : IApplicationLifecycle
+{
+    public void Finish()
+    {
+        IsRunning = false;
+    }
+
+    public bool IsRunning { get; private set; } = true;
+}
\ No newline at end of file
diff --git a/UI/Presentation/Command/CreateCommand.cs b/UI/Presentation/Command/CreateCommand.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8ee03e7a945f196039aff1b3bdf838ac39edd3bb
--- /dev/null
+++ b/UI/Presentation/Command/CreateCommand.cs
@@ -0,0 +1,5 @@
+using UI.Impl;
+
+namespace UI.Presentation.Command;
+
+public class CreateCommand(CreateCommandExecutor executor) : Model.Command("create", executor);
\ No newline at end of file
diff --git a/UI/Presentation/Command/ExitCommand.cs b/UI/Presentation/Command/ExitCommand.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f6b15810cd33062f4074b3936e23252b4c4dea3c
--- /dev/null
+++ b/UI/Presentation/Command/ExitCommand.cs
@@ -0,0 +1,5 @@
+using UI.Impl;
+
+namespace UI.Presentation.Command;
+
+public class ExitCommand(ExitCommandExecutor executor) : Model.Command("exit", executor);
\ No newline at end of file
diff --git a/UI/Presentation/Command/InputCommand.cs b/UI/Presentation/Command/InputCommand.cs
new file mode 100644
index 0000000000000000000000000000000000000000..83ef0dfc041763fc054af765588895b32dc06f34
--- /dev/null
+++ b/UI/Presentation/Command/InputCommand.cs
@@ -0,0 +1,5 @@
+using UI.Impl;
+
+namespace UI.Presentation.Command;
+
+public class InputCommand(InputCommandExecutor executor) : Model.Command("input", executor);
\ No newline at end of file
diff --git a/UI/Presentation/Command/PrintCommand.cs b/UI/Presentation/Command/PrintCommand.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d6b009959a0182679f52a5e88ddbdbfee59ce1df
--- /dev/null
+++ b/UI/Presentation/Command/PrintCommand.cs
@@ -0,0 +1,5 @@
+using UI.Impl;
+
+namespace UI.Presentation.Command;
+
+public class PrintCommand(PrintCommandExecutor executor) : Model.Command("print", executor);
\ No newline at end of file
diff --git a/UI/Presentation/CommandProcessor.cs b/UI/Presentation/CommandProcessor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..11cd5018ea1b3899fb2770fda63a0b5dc329e34e
--- /dev/null
+++ b/UI/Presentation/CommandProcessor.cs
@@ -0,0 +1,40 @@
+using Domain.Exception;
+using UI.Model;
+
+namespace UI.Presentation;
+
+public class CommandProcessor(
+    IEnumerable<ICommand> commands,
+    IConsole console
+) : ICommandProcessor
+{
+    public void ProcessCommands()
+    {
+        var input = console.ReadLine();
+        var args = input.Split(" ");
+        var status = false;
+        foreach (var command in commands)
+        {
+            try
+            {
+                status = command.Execute(args);
+                if (status)
+                {
+                    break;
+                }
+            }
+            catch (Exception e)
+            {
+                console.WriteLine(e.Message);
+            }
+        }
+
+        if (!status)
+            PrintMenu();
+    }
+
+    private void PrintMenu()
+    {
+        console.WriteLine(StringResource.CommandsUsage.Help);
+    }
+}
\ No newline at end of file
diff --git a/UI/Presentation/IApplication.cs b/UI/Presentation/IApplication.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ad6f82144faca372a589e0890bce51a3a45d9054
--- /dev/null
+++ b/UI/Presentation/IApplication.cs
@@ -0,0 +1,7 @@
+namespace UI.Presentation;
+
+public interface IApplication
+{
+    public void Run();
+    public IApplicationLifecycle Lifecycle { get; }
+}
\ No newline at end of file
diff --git a/UI/Presentation/IApplicationLifecycle.cs b/UI/Presentation/IApplicationLifecycle.cs
new file mode 100644
index 0000000000000000000000000000000000000000..61594b1eae463ace9993c02ff0ba98149206b645
--- /dev/null
+++ b/UI/Presentation/IApplicationLifecycle.cs
@@ -0,0 +1,8 @@
+namespace UI.Presentation;
+
+public interface IApplicationLifecycle
+{
+    public void Finish();
+
+    public bool IsRunning { get; }
+}
\ No newline at end of file
diff --git a/UI/Presentation/ICommandProcessor.cs b/UI/Presentation/ICommandProcessor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..55f35e003df69b94d99e9a016c5c0aa4068103d0
--- /dev/null
+++ b/UI/Presentation/ICommandProcessor.cs
@@ -0,0 +1,6 @@
+namespace UI.Presentation;
+
+public interface ICommandProcessor
+{
+    void ProcessCommands();
+}
\ No newline at end of file
diff --git a/UI/Presentation/IConsole.cs b/UI/Presentation/IConsole.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5bf477fd92bfe5b9a7736436d1d94049abf171f6
--- /dev/null
+++ b/UI/Presentation/IConsole.cs
@@ -0,0 +1,8 @@
+namespace UI.Presentation;
+
+public interface IConsole
+{
+    void WriteLine(object message);
+    string ReadLine();
+    void Write(object message);
+}
\ No newline at end of file
diff --git a/UI/Presentation/SystemConsole.cs b/UI/Presentation/SystemConsole.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bcd7896c0a78d2565d998a62ad1d06c7cc008463
--- /dev/null
+++ b/UI/Presentation/SystemConsole.cs
@@ -0,0 +1,10 @@
+namespace UI.Presentation;
+
+public class SystemConsole : IConsole
+{
+    public void WriteLine(object message) => Console.WriteLine(message);
+
+    public string ReadLine() => Console.ReadLine() ?? "";
+
+    public void Write(object message) => Console.Write(message);
+}
\ No newline at end of file
diff --git a/UI/StringResource.cs b/UI/StringResource.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2b1fea6290c1a663d2501e31ebed91604cf2599d
--- /dev/null
+++ b/UI/StringResource.cs
@@ -0,0 +1,47 @@
+namespace UI;
+
+public static class StringResource
+{
+    public static class CommandsUsage
+    {
+        private const string UseLetter = "Используйте: ";
+
+        public const string Create = UseLetter +
+                                     "create <fileName> <arrayType - int/char/varchar> <size> <stringLength - опционально для char и varchar>";
+
+        public const string Input = UseLetter + "input <index> <value>";
+        public const string Print = UseLetter + "print <index>";
+        public const string Exit = UseLetter + "exit";
+
+        public const string Help =
+            "Доступные команды:\n" +
+            "1. " + Create + "\n" +
+            "2. " + Input + "\n" +
+            "3. " + Print + "\n" +
+            "4. " + Exit;
+    }
+
+    public const string InvalidArrayType = "Неправильный тип массива.";
+    public const string ElementNotInitialized = "Элемент не инициализирован.";
+    public const string InvalidSize = "Неправильный размер массива.";
+    public const string CharTypeRequiresStringLength = "Для типа char требуется указать фиксированную длину строки.";
+    public const string InvalidStringLength = "Неверный размер строки.";
+
+    public const string VarcharTypeRequiresMaxStringLength =
+        "Для типа varchar требуется указать максимальную длину строки.";
+    
+    public const string InvalidIndex = "Неверный индекс.";
+    public const string StringLengthOutOfLimit = "Строка превышает максимальный размер";
+    public const string IndexOutOfRange = "Индекс находится за границами массива.";
+    public const string VirtualMemoryNotInitialized = "Виртуальная память не инициализирована.";
+    public const string Exit = "Выключение.";
+    public const string VirtualMemoryInitialized = "Виртуальная память уже инициализирована.";
+    public const string InvalidValue = "Неверное значение.";
+    public const string CreateArrayFirst = "Сначала создайте массив.";
+    public const string ErrorArrayCreating = "Ошибка при создании массива:";
+    public const string ArrayCreated = "Массив создан.";
+    public const string ErrorWhilePerformingCommand = "Ошибка при выполнении команды:";
+    public const string InputSuccess = "Значение успешно записано.";
+    public const string ErrorWriteInt = "Ошибка при записи числа:";
+    public const string ErrorWriteChar = "Ошибка при записи строки:";
+}
\ No newline at end of file
diff --git a/UI/UI.csproj b/UI/UI.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..ecb5d40fae89f6aed1223422805c6f9482cb30a8
--- /dev/null
+++ b/UI/UI.csproj
@@ -0,0 +1,18 @@
+п»ї<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net9.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+    <RootNamespace>UI</RootNamespace>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Domain\Domain.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2" />
+  </ItemGroup>
+
+</Project>
diff --git a/VM.Tests/Domain/CharVirtualMemoryTest.cs b/VM.Tests/Domain/CharVirtualMemoryTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a11b31b3e6a88bbbe67b94e96237008521255df1
--- /dev/null
+++ b/VM.Tests/Domain/CharVirtualMemoryTest.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+using System.Linq;
+using System.Text;
+using JetBrains.Annotations;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using VM.Domain;
+
+namespace VM.Tests.Domain;
+
+[TestClass]
+[TestSubject(typeof(CharVirtualMemory))]
+public class CharVirtualMemoryTests
+{
+    private Mock<IPageBuffer> _mockPageBuffer;
+    private CharVirtualMemory _memory;
+    private const int FixedStringLength = 16; // 16 байтов = 4 int-а
+    private int _size;
+
+    [TestInitialize]
+    public void Setup()
+    {
+        _mockPageBuffer = new Mock<IPageBuffer>();
+        _size = 12;
+        _memory = new CharVirtualMemory(_mockPageBuffer.Object, FixedStringLength, _size);
+    }
+
+    [TestMethod]
+    public void Set_And_Get_SinglePageString_ReturnsCorrectValue()
+    {
+        var page = new Page(0, new BitArray(128), new int[128]);
+        _mockPageBuffer.Setup(m => m.GetPage(0)).Returns(page);
+
+        _memory.Set(0, "Test");
+        var result = _memory.Get(0);
+
+        Assert.AreEqual("Test", result);
+        for (int i = 0; i < FixedStringLength / 4; i++)
+        {
+            Assert.IsTrue(page.BitMap[i]);
+        }
+    }
+
+    [TestMethod]
+    public void Get_UninitializedString_ThrowsException()
+    {
+        var page = new Page(0, new BitArray(128), new int[128]);
+        _mockPageBuffer.Setup(m => m.GetPage(0)).Returns(page);
+
+        Assert.ThrowsException<InvalidOperationException>(() => _memory.Get(0));
+    }
+
+    [TestMethod]
+    public void Set_StringAcrossMultiplePages_CorrectlySplitsData()
+    {
+        var page1 = new Page(0, new BitArray(128), new int[128]);
+        var page2 = new Page(1, new BitArray(128), new int[128]);
+
+        _mockPageBuffer.Setup(m => m.GetPage(0)).Returns(page1);
+        _mockPageBuffer.Setup(m => m.GetPage(1)).Returns(page2);
+
+        string longString = "VeryLongString"; // 14 байтов (разобьется на две страницы)
+
+        _memory.Set(0, longString);
+        var result = _memory.Get(0);
+
+        Assert.AreEqual(longString, result);
+    }
+
+    [TestMethod]
+    public void Set_HugeString_CorrectlySplitsDataAcrossManyPages()
+    {
+        int stringSize = 512 * 4; // 512 байтов = 128 int-ов → займет 4 страницы
+        string hugeString = new string('A', stringSize);
+
+        var pages = new Page[4];
+        for (int i = 0; i < 4; i++)
+        {
+            pages[i] = new Page(i, new BitArray(128), new int[128]);
+            _mockPageBuffer.Setup(m => m.GetPage(i)).Returns(pages[i]);
+        }
+
+        var memory = new CharVirtualMemory(_mockPageBuffer.Object, 512 * 4, _size);
+
+        memory.Set(0, hugeString);
+        var result = memory.Get(0);
+
+        Assert.AreEqual(hugeString, result);
+        for (int i = 0; i < 4; i++)
+        {
+            Assert.IsTrue(pages[i].BitMap.Cast<bool>().Take(32).All(b => b));
+        }
+    }
+
+    [TestMethod]
+    public void Set_StringExactlyFillsPage_WorksCorrectly()
+    {
+        int stringSize = 128 * 4; // Заполняет ровно 1 страницу
+        string exactFit = new string('B', stringSize);
+
+        var page = new Page(0, new BitArray(128), new int[128]);
+        _mockPageBuffer.Setup(m => m.GetPage(0)).Returns(page);
+        var memory = new CharVirtualMemory(_mockPageBuffer.Object, 128 * 4, _size);
+
+        memory.Set(0, exactFit);
+        var result = memory.Get(0);
+
+        Assert.AreEqual(exactFit, result);
+        Assert.IsTrue(page.BitMap.Cast<bool>().Take(32).All(b => b));
+    }
+
+    [TestMethod]
+    public void Set_StringTooLong_ThrowsException()
+    {
+        string tooLong = new string('X', FixedStringLength + 1);
+        Assert.ThrowsException<ArgumentException>(() => _memory.Set(0, tooLong));
+    }
+
+    [TestMethod]
+    public void Set_NegativeIndex_ThrowsException()
+    {
+        Assert.ThrowsException<IndexOutOfRangeException>(() => _memory.Set(-1, "Test"));
+    }
+
+    [TestMethod]
+    public void Get_NegativeIndex_ThrowsException()
+    {
+        Assert.ThrowsException<IndexOutOfRangeException>(() => _memory.Get(-1));
+    }
+
+    [TestMethod]
+    public void Dispose_CallsDisposeOnPageBuffer()
+    {
+        // Arrange
+        var pageBufferMock = new Mock<IPageBuffer>();
+        var virtualMemory = new CharVirtualMemory(pageBufferMock.Object, 10, _size);
+
+        // Act
+        virtualMemory.Dispose();
+
+        // Assert
+        pageBufferMock.Verify(pb => pb.Dispose(), Times.Once);
+    }
+}
\ No newline at end of file
diff --git a/VM.Tests/Domain/IVirtualMemoryTest.cs b/VM.Tests/Domain/IVirtualMemoryTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b72612ed5a2fa97b7b2da53c455d604bd0d73c52
--- /dev/null
+++ b/VM.Tests/Domain/IVirtualMemoryTest.cs
@@ -0,0 +1,85 @@
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using VM.Domain;
+
+namespace VM.Tests.Domain;
+
+[TestClass]
+public class VirtualMemoryTests
+{
+    private Mock<IVirtualMemory<string>> _mockStringMemory;
+
+    private class StringVirtualMemory(IVirtualMemory<string> virtualMemory) : IVirtualMemory<string>
+    {
+        public void Dispose()
+        {
+            virtualMemory.Dispose();
+        }
+
+        public void Set(int index, string value)
+        {
+            virtualMemory.Set(index, value);
+        }
+
+        public string Get(int index)
+        {
+            return virtualMemory.Get(index);
+        }
+    }
+
+    [TestInitialize]
+    public void Setup()
+    {
+        _mockStringMemory = new Mock<IVirtualMemory<string>>();
+    }
+
+    [TestMethod]
+    public void IVirtualMemory_Set_ShouldCallGenericSet_WhenValueIsCorrectType()
+    {
+        // Arrange
+        var index = 1;
+        var value = "Test String";
+
+        _mockStringMemory.Setup(m => m.Set(index, value));
+
+        IVirtualMemory virtualMemory = new StringVirtualMemory(_mockStringMemory.Object);
+        // Act
+        virtualMemory.Set(index, value);
+
+        // Assert
+        _mockStringMemory.Verify(m => m.Set(index, value), Times.Once);
+    }
+
+    [TestMethod]
+    [ExpectedException(typeof(ArgumentException))]
+    public void IVirtualMemory_Set_ShouldThrowException_WhenValueIsIncorrectType()
+    {
+        // Arrange
+        var index = 2;
+        var invalidValue = 42; // Целое число вместо строки
+
+        // Act
+        IVirtualMemory virtualMemory = new StringVirtualMemory(_mockStringMemory.Object);
+        virtualMemory.Set(index, invalidValue);
+    }
+
+    [TestMethod]
+    public void IVirtualMemory_Get_ShouldCallGenericGet_AndReturnCorrectValue()
+    {
+        // Arrange
+        var index = 3;
+        var expectedValue = "Another Test String";
+
+        _mockStringMemory.Setup(m => m.Get(index)).Returns(expectedValue);
+
+        IVirtualMemory virtualMemory = new StringVirtualMemory(_mockStringMemory.Object);
+
+        // Act
+        var result = virtualMemory.Get(index);
+
+        // Assert
+        Assert.AreEqual(expectedValue, result);
+        _mockStringMemory.Verify(m => m.Get(index), Times.Once);
+    }
+}
diff --git a/VM.Tests/Domain/IntVirtualMemoryTest.cs b/VM.Tests/Domain/IntVirtualMemoryTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..20453d6c5c545c6e42a3e462ee2e5b42dba17369
--- /dev/null
+++ b/VM.Tests/Domain/IntVirtualMemoryTest.cs
@@ -0,0 +1,134 @@
+using VM.Domain;
+
+namespace VM.Tests.Domain;
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using System;
+using System.Collections;
+
+[TestClass]
+public class IntVirtualMemoryTests
+{
+    private const int ElementsPerPage = 128;
+    private Mock<IPageBuffer> _pageBufferMock = null!;
+    private IntVirtualMemory _virtualMemory = null!;
+    private int _size;
+
+    [TestInitialize]
+    public void Setup()
+    {
+        _pageBufferMock = new Mock<IPageBuffer>();
+        _size = 12;
+        _virtualMemory = new IntVirtualMemory(_pageBufferMock.Object, _size);
+    }
+
+    [TestMethod]
+    public void Set_SetsValueCorrectly()
+    {
+        var page = CreateMockPage(0);
+
+        _pageBufferMock
+            .Setup(pb => pb.GetPage(0))
+            .Returns(page);
+
+        _virtualMemory.Set(5, 42);
+
+        Assert.AreEqual(42, page.Data[5]);
+        Assert.IsTrue(page.BitMap[5]);
+
+        _pageBufferMock.Verify(pb => pb.MarkPageModified(0), Times.Once);
+    }
+
+    [TestMethod]
+    public void Get_GetsValueCorrectly()
+    {
+        var page = CreateMockPage(0);
+        page.Data[5] = 42;
+        page.BitMap[5] = true;
+
+        _pageBufferMock
+            .Setup(pb => pb.GetPage(0))
+            .Returns(page);
+
+        int value = _virtualMemory.Get(5);
+
+        Assert.AreEqual(42, value);
+    }
+
+    [TestMethod]
+    [ExpectedException(typeof(InvalidOperationException))]
+    public void Get_UninitializedValue_ThrowsException()
+    {
+        var page = CreateMockPage(0);
+
+        _pageBufferMock
+            .Setup(pb => pb.GetPage(0))
+            .Returns(page);
+
+        _virtualMemory.Get(5); // Ожидаем исключение
+    }
+
+    [TestMethod]
+    [ExpectedException(typeof(IndexOutOfRangeException))]
+    public void Set_NegativeIndex_ThrowsException()
+    {
+        _virtualMemory.Set(-1, 42);
+    }
+
+    [TestMethod]
+    [ExpectedException(typeof(IndexOutOfRangeException))]
+    public void Get_NegativeIndex_ThrowsException()
+    {
+        _virtualMemory.Get(-1);
+    }
+
+    [TestMethod]
+    [ExpectedException(typeof(IndexOutOfRangeException))]
+    public void Set_IndexBeyondBitMap_ThrowsException()
+    {
+        var page = CreateMockPage(0, bitMapSize: 5); // Меньший размер битовой карты
+
+        _pageBufferMock
+            .Setup(pb => pb.GetPage(0))
+            .Returns(page);
+
+        _virtualMemory.Set(10, 42);
+    }
+
+    [TestMethod]
+    [ExpectedException(typeof(IndexOutOfRangeException))]
+    public void Get_IndexBeyondBitMap_ThrowsException()
+    {
+        var page = CreateMockPage(0, bitMapSize: 5); // Меньший размер битовой карты
+
+        _pageBufferMock
+            .Setup(pb => pb.GetPage(0))
+            .Returns(page);
+
+        _virtualMemory.Get(10);
+    }
+
+    private IPage CreateMockPage(int pageIndex, int bitMapSize = ElementsPerPage)
+    {
+        var mock = new Mock<IPage>();
+        mock.Setup(p => p.PageIndex).Returns(pageIndex);
+        mock.Setup(p => p.BitMap).Returns(new BitArray(bitMapSize));
+        mock.Setup(p => p.Data).Returns(new int[ElementsPerPage]);
+        return mock.Object;
+    }
+
+    [TestMethod]
+    public void Dispose_CallsDisposeOnPageBuffer()
+    {
+        // Arrange
+        var pageBufferMock = new Mock<IPageBuffer>();
+        var virtualMemory = new IntVirtualMemory(pageBufferMock.Object, _size);
+
+        // Act
+        virtualMemory.Dispose();
+
+        // Assert
+        pageBufferMock.Verify(pb => pb.Dispose(), Times.Once);
+    }
+}
\ No newline at end of file
diff --git a/VM.Tests/Domain/PageBufferTest.cs b/VM.Tests/Domain/PageBufferTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1e7227f310b64fd5ae706cb76f507ffd61efbf20
--- /dev/null
+++ b/VM.Tests/Domain/PageBufferTest.cs
@@ -0,0 +1,159 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using JetBrains.Annotations;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using VM.Domain;
+
+namespace VM.Tests.Domain;
+
+[TestClass]
+[TestSubject(typeof(PageBuffer))]
+public class PageBufferTest
+{
+    private Mock<ISwapFile> _swapFileMock;
+    private Mock<IDateTimeService> _dateTimeServiceMock;
+    private PageBuffer _buffer;
+    private readonly DateTime _dateTime = DateTime.Now;
+
+    [TestInitialize]
+    public void Setup()
+    {
+        _swapFileMock = new Mock<ISwapFile>();
+        _dateTimeServiceMock = new Mock<IDateTimeService>();
+        _dateTimeServiceMock.Setup(d => d.CurrentDateTime()).Returns(_dateTime);
+        _buffer = new PageBuffer(_swapFileMock.Object, _dateTimeServiceMock.Object, 2);
+    }
+
+    [TestMethod]
+    public void GetPage_ShouldLoadPage_IfNotInBuffer()
+    {
+        var page = new Page(0, new BitArray(128, true), new int[128]);
+        _swapFileMock.Setup(s => s.LoadPage(0)).Returns(page);
+
+        var loadedPage = _buffer.GetPage(0);
+
+        Assert.AreEqual(page, loadedPage);
+        _swapFileMock.Verify(s => s.LoadPage(0), Times.Once);
+    }
+
+    [TestMethod]
+    public void GetPage_ShouldNotReloadPage_IfAlreadyInBuffer()
+    {
+        var page = new Page(0, new BitArray(128, true), new int[128]);
+        _swapFileMock.Setup(s => s.LoadPage(0)).Returns(page);
+
+        _buffer.GetPage(0);
+        _swapFileMock.Invocations.Clear();
+
+        var loadedPage = _buffer.GetPage(0);
+
+        Assert.AreEqual(page, loadedPage);
+        _swapFileMock.Verify(s => s.LoadPage(It.IsAny<int>()), Times.Never);
+    }
+
+    [TestMethod]
+    public void MarkPageModified_ShouldSetIsModified_IfPageIsInBuffer()
+    {
+        var page = new Page(0, new BitArray(128, true), new int[128]);
+        _swapFileMock.Setup(s => s.LoadPage(0)).Returns(page);
+
+        _buffer.GetPage(0);
+
+        _buffer.MarkPageModified(0);
+
+        Assert.IsTrue(page.IsModified);
+    }
+
+    [TestMethod]
+    public void ReplaceOldestPage_ShouldSaveAndRemoveOldestPage_IfModified()
+    {
+        // Arrange
+        var page1 = new Page(0, new BitArray(128, true), new int[128])
+        {
+            AccessTime = DateTime.Now.AddMinutes(-10),
+            IsModified = true
+        };
+        var page2 = new Page(1, new BitArray(128, true), new int[128])
+        {
+            AccessTime = DateTime.Now.AddMinutes(-5),
+            IsModified = false
+        };
+        var page3 = new Page(2, new BitArray(128, true), new int[128]); // Новая страница
+
+        _swapFileMock.Setup(s => s.LoadPage(2)).Returns(page3);
+        _swapFileMock.Setup(s => s.SavePage(page1)).Verifiable(); // Должен быть вызван `SavePage`
+
+        _buffer.GetType()
+            .GetField("_pages", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
+            ?.SetValue(_buffer, new List<IPage> { page1, page2 });
+
+        // Act
+        _buffer.GetPage(2); // Должен вызвать ReplaceOldestPage и удалить `page1`
+
+        // Assert
+        _swapFileMock.Verify(s => s.SavePage(page1), Times.Once); // Проверяем, что измененная страница сохранена
+        var pages = (List<IPage>)_buffer.GetType()
+            .GetField("_pages", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
+            ?.GetValue(_buffer);
+        Assert.IsFalse(pages.Contains(page1)); // Проверяем, что `page1` удалена
+    }[TestMethod]
+    public void GetPage_ShouldUpdateAccessTime()
+    {
+        var page = new Page(0, new BitArray(128, true), new int[128]);
+        _swapFileMock.Setup(s => s.LoadPage(0)).Returns(page);
+
+        _buffer.GetPage(0);
+
+        Assert.AreEqual(_dateTime, page.AccessTime);
+    }
+
+    [TestMethod]
+    public void ReplaceOldestPage_ShouldRemoveOldestPage_IfNotModified()
+    {
+        var page1 = new Page(0, new BitArray(128, true), new int[128])
+        {
+            AccessTime = DateTime.Now.AddMinutes(-10),
+            IsModified = false
+        };
+        var page2 = new Page(1, new BitArray(128, true), new int[128])
+        {
+            AccessTime = DateTime.Now.AddMinutes(-5)
+        };
+        var page3 = new Page(2, new BitArray(128, true), new int[128]);
+
+        _swapFileMock.Setup(s => s.LoadPage(2)).Returns(page3);
+
+        _buffer.GetType()
+            .GetField("_pages", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
+            ?.SetValue(_buffer, new List<IPage> { page1, page2 });
+
+        _buffer.GetPage(2);
+
+        var pages = (List<IPage>)_buffer.GetType()
+            .GetField("_pages", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
+            ?.GetValue(_buffer);
+
+        Assert.IsFalse(pages.Contains(page1));
+        _swapFileMock.Verify(s => s.SavePage(It.IsAny<IPage>()), Times.Never);
+    }
+
+    [TestMethod]
+    public void Dispose_ShouldSaveAllPagesAndDisposeSwapFile()
+    {
+        var page1 = new Mock<IPage>();
+        var page2 = new Mock<IPage>();
+
+        _buffer.GetType()
+            .GetField("_pages", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
+            ?.SetValue(_buffer, new List<IPage> { page1.Object, page2.Object });
+
+        _buffer.Dispose();
+
+        _swapFileMock.Verify(s => s.SavePage(page1.Object), Times.Once);
+        _swapFileMock.Verify(s => s.SavePage(page2.Object), Times.Once);
+        _swapFileMock.Verify(s => s.Dispose(), Times.Once);
+    }
+
+}
\ No newline at end of file
diff --git a/VM.Tests/Domain/PageTest.cs b/VM.Tests/Domain/PageTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..51c0eea9821d750cf702c84735897fbd552a54af
--- /dev/null
+++ b/VM.Tests/Domain/PageTest.cs
@@ -0,0 +1,88 @@
+using VM.Domain;
+
+namespace VM.Tests.Domain;
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Collections;
+
+[TestClass]
+public class PageTests
+{
+    [TestMethod]
+    public void Constructor_ValidParameters_ShouldInitializeCorrectly()
+    {
+        var bitMap = new BitArray(128);
+        var data = new int[128];
+
+        var page = new Page(1, bitMap, data);
+
+        Assert.AreEqual(1, page.PageIndex);
+        Assert.IsNotNull(page.BitMap);
+        Assert.IsNotNull(page.Data);
+        Assert.IsFalse(page.IsModified);
+        Assert.AreEqual(128, page.BitMap.Length);
+        Assert.AreEqual(128, page.Data.Length);
+    }
+
+    [TestMethod]
+    [ExpectedException(typeof(ArgumentException))]
+    public void Constructor_NullBitMap_ShouldThrowException()
+    {
+        var data = new int[128];
+        var page = new Page(1, null, data);
+    }
+
+    [TestMethod]
+    [ExpectedException(typeof(ArgumentException))]
+    public void Constructor_InvalidBitMapSize_ShouldThrowException()
+    {
+        var bitMap = new BitArray(127);
+        var data = new int[128];
+        var page = new Page(1, bitMap, data);
+    }
+
+    [TestMethod]
+    [ExpectedException(typeof(ArgumentException))]
+    public void Constructor_NullData_ShouldThrowException()
+    {
+        var bitMap = new BitArray(128);
+        var page = new Page(1, bitMap, null);
+    }
+
+    [TestMethod]
+    [ExpectedException(typeof(ArgumentException))]
+    public void Constructor_InvalidDataSize_ShouldThrowException()
+    {
+        var bitMap = new BitArray(128);
+        var data = new int[127];
+        var page = new Page(1, bitMap, data);
+    }
+
+    [TestMethod]
+    public void AccessTime_ShouldUpdateCorrectly()
+    {
+        var bitMap = new BitArray(128);
+        var data = new int[128];
+
+        var page = new Page(1, bitMap, data);
+        var initialTime = page.AccessTime;
+
+        System.Threading.Thread.Sleep(10);
+        page.AccessTime = DateTime.Now;
+
+        Assert.IsTrue(page.AccessTime > initialTime);
+    }
+
+    [TestMethod]
+    public void IsModified_ShouldBeSettable()
+    {
+        var bitMap = new BitArray(128);
+        var data = new int[128];
+
+        var page = new Page(1, bitMap, data);
+        page.IsModified = true;
+
+        Assert.IsTrue(page.IsModified);
+    }
+}
diff --git a/VM.Tests/Domain/SwapFileTest.cs b/VM.Tests/Domain/SwapFileTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..43c35ed4aa59dcf1c7e4fa179380b0d863345a18
--- /dev/null
+++ b/VM.Tests/Domain/SwapFileTest.cs
@@ -0,0 +1,65 @@
+using VM.Domain;
+
+namespace VM.Tests.Domain;
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.IO;
+using System.Collections;
+
+[TestClass]
+public class SwapFileTests
+{
+    private const string TestFileName = "test.vm";
+
+    [TestInitialize]
+    public void Setup()
+    {
+        if (File.Exists(TestFileName))
+            File.Delete(TestFileName);
+    }
+
+    [TestCleanup]
+    public void Cleanup()
+    {
+        if (File.Exists(TestFileName))
+            File.Delete(TestFileName);
+    }
+
+    [TestMethod]
+    public void SwapFile_ShouldCreateFileWithCorrectSignature()
+    {
+        using var swapFile = new SwapFile(TestFileName, 10000);
+
+        using var fs = new FileStream(TestFileName, FileMode.Open, FileAccess.Read);
+        using var reader = new BinaryReader(fs);
+
+        var signature = reader.ReadBytes(2);
+        CollectionAssert.AreEqual("VM"u8.ToArray(), signature, "Файл должен начинаться с сигнатуры 'VM'.");
+    }
+
+    [TestMethod]
+    public void SwapFile_ShouldLoadAndSavePageCorrectly()
+    {
+        using var swapFile = new SwapFile(TestFileName, 10000);
+        var page = new Page(0, new BitArray(128, true), new int[128]);
+        for (var i = 0; i < 128; i++) page.Data[i] = i;
+
+        swapFile.SavePage(page);
+        var loadedPage = swapFile.LoadPage(0);
+
+        for (var i = 0; i < 128; i++)
+        {
+            Assert.AreEqual(i, loadedPage.Data[i], $"Данные в ячейке {i} не совпадают.");
+        }
+    }
+
+    [TestMethod]
+    public void SwapFile_LoadPage_ShouldThrowException_WhenOutOfBounds()
+    {
+        using var swapFile = new SwapFile(TestFileName, 10);
+
+        Assert.Throws<InvalidOperationException>(() => swapFile.LoadPage(1000));
+    }
+}
+
diff --git a/VM.Tests/Domain/SystemDateTimeServiceTest.cs b/VM.Tests/Domain/SystemDateTimeServiceTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c9d64c1fa61faf463df1d9892bfd6d7d75c37ea5
--- /dev/null
+++ b/VM.Tests/Domain/SystemDateTimeServiceTest.cs
@@ -0,0 +1,28 @@
+using System;
+using JetBrains.Annotations;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using VM.Domain;
+
+namespace VM.Tests.Domain;
+
+[TestClass]
+[TestSubject(typeof(SystemDateTimeService))]
+public class SystemDateTimeServiceTest
+{
+    [TestMethod]
+    public void CurrentDateTime_ShouldReturnCurrentSystemTime()
+    {
+        // Arrange
+        var service = new SystemDateTimeService();
+        var beforeCall = DateTime.Now;
+
+        // Act
+        var result = service.CurrentDateTime();
+
+        var afterCall = DateTime.Now;
+
+        // Assert
+        Assert.IsTrue(result >= beforeCall && result <= afterCall, 
+            $"Returned time {result} is not within expected range {beforeCall} - {afterCall}");
+    }
+}
diff --git a/VM.Tests/Domain/VarcharVirtualMemoryTest.cs b/VM.Tests/Domain/VarcharVirtualMemoryTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f1af0963465c5a32779db22d2221d8e4b49343a8
--- /dev/null
+++ b/VM.Tests/Domain/VarcharVirtualMemoryTest.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using VM.Domain;
+
+namespace VM.Tests.Domain;
+
+[TestClass]
+public class VarcharVirtualMemoryTest
+{
+    private Mock<ISwapFile> _swapFileMock;
+    private string _testFileName;
+    private VarcharVirtualMemory _memory;
+    private Page _testPage;
+    private int _size;
+    [TestInitialize]
+    public void Setup()
+    {
+        _swapFileMock = new Mock<ISwapFile>();
+        _testFileName = "test_data.dat";
+        File.Delete(_testFileName);
+
+        _testPage = new Page(0, new BitArray(128, false), new int[128]);
+        _swapFileMock.Setup(s => s.LoadPage(It.IsAny<int>())).Returns(_testPage);
+        _size = 12;
+        _memory = new VarcharVirtualMemory(_swapFileMock.Object, _testFileName, 50, _size);
+    }
+
+    [TestCleanup]
+    public void Cleanup()
+    {
+        _memory.Dispose();
+        File.Delete(_testFileName);
+    }
+
+    [TestMethod]
+    public void Set_ShouldStoreStringValue()
+    {
+        // Arrange
+        var value = "Hello, World!";
+        var index = 5;
+
+        // Act
+        _memory.Set(index, value);
+
+        // Assert
+        Assert.IsTrue(_testPage.BitMap[index]);
+        _swapFileMock.Verify(s => s.SavePage(_testPage), Times.Once);
+
+        // Проверяем, что данные записаны в файл
+        using var reader = new BinaryReader(File.OpenRead(_testFileName), Encoding.UTF8);
+        reader.BaseStream.Seek(_testPage.Data[index], SeekOrigin.Begin);
+        var length = reader.ReadInt32();
+        var storedBytes = reader.ReadBytes(length);
+        var storedValue = Encoding.UTF8.GetString(storedBytes);
+
+        Assert.AreEqual(value, storedValue);
+    }
+
+    [TestMethod]
+    public void Get_ShouldRetrieveStoredStringValue()
+    {
+        // Arrange
+        var value = "Test String";
+        var index = 10;
+        _memory.Set(index, value);
+
+        // Act
+        var retrievedValue = _memory.Get(index);
+
+        // Assert
+        Assert.AreEqual(value, retrievedValue);
+    }
+
+    [TestMethod]
+    [ExpectedException(typeof(IndexOutOfRangeException))]
+    public void Set_ShouldThrowException_WhenIndexIsNegative()
+    {
+        _memory.Set(-1, "Invalid");
+    }
+
+    [TestMethod]
+    [ExpectedException(typeof(ArgumentException))]
+    public void Set_ShouldThrowException_WhenStringExceedsMaxSize()
+    {
+        _memory.Set(0, new string('a', 51)); // Превышает лимит в 50 символов
+    }
+
+    [TestMethod]
+    [ExpectedException(typeof(IndexOutOfRangeException))]
+    public void Get_ShouldThrowException_WhenIndexIsNegative()
+    {
+        _memory.Get(-1);
+    }
+
+    [TestMethod]
+    [ExpectedException(typeof(InvalidOperationException))]
+    public void Get_ShouldThrowException_WhenElementIsNotInitialized()
+    {
+        _memory.Get(20); // Нет вызова Set -> элемент неинициализирован
+    }
+
+    [TestMethod]
+    public void Dispose_ShouldCloseResources()
+    {
+        _memory.Dispose();
+
+        Assert.ThrowsException<ArgumentException>(() =>
+        {
+            using var reader = new BinaryReader(_memory.GetType()
+                .GetField("_dataFile",
+                    System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
+                ?.GetValue(_memory) as FileStream);
+            reader.ReadByte();
+        });
+
+        _swapFileMock.Verify(s => s.Dispose(), Times.Once);
+    }
+}
\ No newline at end of file
diff --git a/VM.Tests/VM.Tests.csproj b/VM.Tests/VM.Tests.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..e136fd2861790ea924491d52b9eb4c3734b6c99f
--- /dev/null
+++ b/VM.Tests/VM.Tests.csproj
@@ -0,0 +1,28 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  
+    <PropertyGroup>
+        <TargetFramework>net9.0</TargetFramework>
+        <LangVersion>latest</LangVersion>
+        <ImplicitUsings>enable</ImplicitUsings>
+        <Nullable>enable</Nullable>
+        <IsPackable>false</IsPackable>
+    </PropertyGroup>
+
+    <ItemGroup>
+        <PackageReference Include="JetBrains.Annotations" Version="2025.1.0-eap1"/>
+        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2"/>
+        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0"/>
+        <PackageReference Include="Moq" Version="4.20.72"/>
+        <PackageReference Include="MSTest.TestAdapter" Version="3.8.2"/>
+        <PackageReference Include="MSTest.TestFramework" Version="3.8.2"/>
+    </ItemGroup>
+
+    <ItemGroup>
+        <ProjectReference Include="..\VM\VM.csproj"/>
+    </ItemGroup>
+
+    <ItemGroup>
+        <Folder Include="Data\Service\"/>
+    </ItemGroup>
+
+</Project>
\ No newline at end of file
diff --git a/VM/Domain/CharVirtualMemory.cs b/VM/Domain/CharVirtualMemory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..876eef4516e779ce9a64fd1f81d4846f8d339b9c
--- /dev/null
+++ b/VM/Domain/CharVirtualMemory.cs
@@ -0,0 +1,130 @@
+namespace VM.Domain;
+
+using System;
+using System.Text;
+
+/// <summary>
+/// Represents a virtual memory for storing fixed-length strings.
+/// </summary>
+public class CharVirtualMemory : IVirtualMemory<string>
+{
+    private const int ElementsPerPage = 128;
+    private readonly IPageBuffer _pageBuffer;
+    private readonly int _alignedFixedStringLength;
+    private readonly int _realFixedStringLength;
+    private readonly int _intPerString;
+    private readonly int _size;
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="CharVirtualMemory"/> class.
+    /// </summary>
+    /// <param name="pageBuffer">The page buffer used to manage pages of memory.</param>
+    /// <param name="fixedStringLength">The fixed length of the strings to be stored.</param>
+    /// <param name="size">The length of the array</param>
+    /// <exception cref="ArgumentOutOfRangeException">Thrown when the fixed string length is negative or zero.</exception>
+    public CharVirtualMemory(IPageBuffer pageBuffer, int fixedStringLength, int size)
+    {
+        ArgumentOutOfRangeException.ThrowIfNegativeOrZero(fixedStringLength, "Длина строки");
+
+        _pageBuffer = pageBuffer;
+        _alignedFixedStringLength = (fixedStringLength + 3) / 4 * 4;
+        _realFixedStringLength = fixedStringLength;
+        _intPerString = _alignedFixedStringLength / 4;
+        _size = size;
+    }
+
+    /// <summary>
+    /// Sets the string value at the specified index in the virtual memory.
+    /// </summary>
+    /// <param name="index">The index at which to set the value.</param>
+    /// <param name="value">The string value to set.</param>
+    /// <exception cref="IndexOutOfRangeException">Thrown when the index is out of range.</exception>
+    /// <exception cref="ArgumentException">Thrown when the string is too long.</exception>
+    public void Set(int index, string value)
+    {
+        if (index < 0 || index >= _size)
+            throw new IndexOutOfRangeException("Индекс вне границ массива");
+
+        if (Encoding.UTF8.GetByteCount(value) > _realFixedStringLength)
+            throw new ArgumentException("Строка слишком длинная");
+
+        byte[] bytes = new byte[_alignedFixedStringLength];
+        Encoding.UTF8.GetBytes(value, 0, value.Length, bytes, 0);
+
+        int startElementIndex = index * _intPerString;
+        int remainingInts = _intPerString;
+
+        while (remainingInts > 0)
+        {
+            int pageIndex = startElementIndex / ElementsPerPage;
+            int localIndex = startElementIndex % ElementsPerPage;
+
+            var page = _pageBuffer.GetPage(pageIndex);
+
+            int spaceInPage = ElementsPerPage - localIndex;
+            int toWrite = Math.Min(spaceInPage, remainingInts);
+
+            for (int i = 0; i < toWrite; i++)
+            {
+                page.Data[localIndex + i] = BitConverter.ToInt32(bytes, (i + (_intPerString - remainingInts)) * 4);
+                page.BitMap[localIndex + i] = true;
+            }
+
+            _pageBuffer.MarkPageModified(pageIndex);
+
+            remainingInts -= toWrite;
+            startElementIndex += toWrite;
+        }
+    }
+
+    /// <summary>
+    /// Gets the string value at the specified index in the virtual memory.
+    /// </summary>
+    /// <param name="index">The index from which to get the value.</param>
+    /// <returns>The string value at the specified index.</returns>
+    /// <exception cref="IndexOutOfRangeException">Thrown when the index is out of range.</exception>
+    /// <exception cref="InvalidOperationException">Thrown when the element is not initialized.</exception>
+    public string Get(int index)
+    {
+        if (index < 0)
+            throw new IndexOutOfRangeException("Индекс вне границ массива");
+
+        byte[] bytes = new byte[_alignedFixedStringLength];
+        int startElementIndex = index * _intPerString;
+        int remainingInts = _intPerString;
+
+        while (remainingInts > 0)
+        {
+            int pageIndex = startElementIndex / ElementsPerPage;
+            int localIndex = startElementIndex % ElementsPerPage;
+
+            var page = _pageBuffer.GetPage(pageIndex);
+
+            int spaceInPage = ElementsPerPage - localIndex;
+            int toRead = Math.Min(spaceInPage, remainingInts);
+
+            for (int i = 0; i < toRead; i++)
+            {
+                if (!page.BitMap[localIndex + i])
+                    throw new InvalidOperationException("Элемент не инициализирован");
+
+                Array.Copy(BitConverter.GetBytes(page.Data[localIndex + i]), 0, bytes,
+                    (i + (_intPerString - remainingInts)) * 4, 4);
+            }
+
+            remainingInts -= toRead;
+            startElementIndex += toRead;
+        }
+
+        return Encoding.UTF8.GetString(bytes).TrimEnd('\0');
+    }
+
+    /// <summary>
+    /// Disposes the resources used by the virtual memory.
+    /// </summary>
+    public void Dispose()
+    {
+        _pageBuffer.Dispose();
+        GC.SuppressFinalize(this);
+    }
+}
\ No newline at end of file
diff --git a/VM/Domain/IDateTimeService.cs b/VM/Domain/IDateTimeService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b7be7f7dfd4bc05bf021188e3287736d028a32c3
--- /dev/null
+++ b/VM/Domain/IDateTimeService.cs
@@ -0,0 +1,13 @@
+namespace VM.Domain;
+
+/// <summary>
+/// Provides an interface for obtaining the current date and time.
+/// </summary>
+public interface IDateTimeService
+{
+    /// <summary>
+    /// Gets the current date and time.
+    /// </summary>
+    /// <returns>The current date and time.</returns>
+    DateTime CurrentDateTime();
+}
\ No newline at end of file
diff --git a/VM/Domain/IPage.cs b/VM/Domain/IPage.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e57425c93f082c53a62914336bf719ae57635487
--- /dev/null
+++ b/VM/Domain/IPage.cs
@@ -0,0 +1,34 @@
+using System.Collections;
+
+namespace VM.Domain;
+
+/// <summary>
+/// Represents a page in the virtual memory domain.
+/// </summary>
+public interface IPage
+{
+    /// <summary>
+    /// Gets the index of the page.
+    /// </summary>
+    int PageIndex { get; }
+
+    /// <summary>
+    /// Gets or sets the last access time of the page.
+    /// </summary>
+    DateTime AccessTime { get; set; }
+
+    /// <summary>
+    /// Gets or sets a value indicating whether the page has been modified.
+    /// </summary>
+    bool IsModified { get; set; }
+
+    /// <summary>
+    /// Gets the bitmap representing the page.
+    /// </summary>
+    BitArray BitMap { get; }
+
+    /// <summary>
+    /// Gets the data contained in the page.
+    /// </summary>
+    int[] Data { get; }
+}
\ No newline at end of file
diff --git a/VM/Domain/IPageBuffer.cs b/VM/Domain/IPageBuffer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4c7cec9a72bf8fb8ab9967cecc05389196621ec9
--- /dev/null
+++ b/VM/Domain/IPageBuffer.cs
@@ -0,0 +1,20 @@
+namespace VM.Domain;
+
+/// <summary>
+/// Provides an interface for managing pages in a buffer.
+/// </summary>
+public interface IPageBuffer : IDisposable
+{
+    /// <summary>
+    /// Gets the page at the specified index.
+    /// </summary>
+    /// <param name="pageIndex">The index of the page to retrieve.</param>
+    /// <returns>The page at the specified index.</returns>
+    public IPage GetPage(int pageIndex);
+
+    /// <summary>
+    /// Marks the page at the specified index as modified.
+    /// </summary>
+    /// <param name="pageIndex">The index of the page to mark as modified.</param>
+    public void MarkPageModified(int pageIndex);
+}
\ No newline at end of file
diff --git a/VM/Domain/ISwapFile.cs b/VM/Domain/ISwapFile.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f448844d71ecacb2689cf16f7147c22d33b8f247
--- /dev/null
+++ b/VM/Domain/ISwapFile.cs
@@ -0,0 +1,20 @@
+namespace VM.Domain;
+
+/// <summary>
+/// Represents an interface for a swap file used in virtual memory management.
+/// </summary>
+public interface ISwapFile : IDisposable
+{
+    /// <summary>
+    /// Loads the page at the specified index.
+    /// </summary>
+    /// <param name="pageIndex">The index of the page to load.</param>
+    /// <returns>The loaded page.</returns>
+    public IPage LoadPage(int pageIndex);
+
+    /// <summary>
+    /// Saves the specified page to the swap file.
+    /// </summary>
+    /// <param name="page">The page to save.</param>
+    public void SavePage(IPage page);
+}
\ No newline at end of file
diff --git a/VM/Domain/IVirtualMemory.cs b/VM/Domain/IVirtualMemory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..078aaf50084eacbeedf6dc2e497e6bf2a33e3cde
--- /dev/null
+++ b/VM/Domain/IVirtualMemory.cs
@@ -0,0 +1,70 @@
+namespace VM.Domain;
+
+/// <summary>
+/// Interface representing a virtual memory that supports setting and getting values by index.
+/// </summary>
+public interface IVirtualMemory : IDisposable
+{
+    /// <summary>
+    /// Sets the value at the specified index.
+    /// </summary>
+    /// <param name="index">The index at which to set the value.</param>
+    /// <param name="value">The value to set.</param>
+    void Set(int index, object value);
+
+    /// <summary>
+    /// Gets the value at the specified index.
+    /// </summary>
+    /// <param name="index">The index from which to get the value.</param>
+    /// <returns>The value at the specified index.</returns>
+    object Get(int index);
+}
+
+/// <summary>
+/// Generic interface representing a virtual memory that supports setting and getting values of a specific type by index.
+/// </summary>
+/// <typeparam name="T">The type of values stored in the virtual memory.</typeparam>
+public interface IVirtualMemory<T> : IVirtualMemory
+{
+    /// <summary>
+    /// Sets the value of type <typeparamref name="T"/> at the specified index.
+    /// </summary>
+    /// <param name="index">The index at which to set the value.</param>
+    /// <param name="value">The value of type <typeparamref name="T"/> to set.</param>
+    void Set(int index, T value);
+
+    /// <summary>
+    /// Gets the value of type <typeparamref name="T"/> at the specified index.
+    /// </summary>
+    /// <param name="index">The index from which to get the value.</param>
+    /// <returns>The value of type <typeparamref name="T"/> at the specified index.</returns>
+    new T Get(int index);
+
+    /// <summary>
+    /// Gets the value at the specified index as an object.
+    /// </summary>
+    /// <param name="index">The index from which to get the value.</param>
+    /// <returns>The value at the specified index as an object.</returns>
+    object IVirtualMemory.Get(int index)
+    {
+        return Get(index);
+    }
+
+    /// <summary>
+    /// Sets the value at the specified index as an object.
+    /// </summary>
+    /// <param name="index">The index at which to set the value.</param>
+    /// <param name="value">The value to set as an object.</param>
+    /// <exception cref="ArgumentException">Thrown when the value is not of type <typeparamref name="T"/>.</exception>
+    void IVirtualMemory.Set(int index, object value)
+    {
+        if (value is T tValue)
+        {
+            Set(index, tValue);
+        }
+        else
+        {
+            throw new ArgumentException("Invalid value type");
+        }
+    }
+}
\ No newline at end of file
diff --git a/VM/Domain/IntVirtualMemory.cs b/VM/Domain/IntVirtualMemory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..42d1ad37d8ed4f7233dc87179e90c51664678274
--- /dev/null
+++ b/VM/Domain/IntVirtualMemory.cs
@@ -0,0 +1,77 @@
+namespace VM.Domain;
+
+/// <summary>
+/// Represents a virtual memory implementation for integers.
+/// </summary>
+/// <param name="pageBuffer">The page buffer used to manage memory pages.</param>
+public class IntVirtualMemory(IPageBuffer pageBuffer, int size) : IVirtualMemory<int>
+{
+    private const int ElementsPerPage = 128;
+
+    /// <summary>
+    /// Sets the value at the specified index in the virtual memory.
+    /// </summary>
+    /// <param name="index">The index at which to set the value.</param>
+    /// <param name="value">The value to set.</param>
+    /// <exception cref="IndexOutOfRangeException">Thrown when the index is out of range.</exception>
+    public void Set(int index, int value)
+    {
+        if (index < 0 || index >= size)
+        {
+            throw new IndexOutOfRangeException("Индекс вне границ массива");
+        }
+
+        var pageIndex = index / ElementsPerPage;
+        var localIndex = index % ElementsPerPage;
+        var page = pageBuffer.GetPage(pageIndex);
+
+        if (localIndex >= page.BitMap.Length)
+        {
+            throw new IndexOutOfRangeException("Локальный индекс выходит за границы битовой карты страницы");
+        }
+
+        page.Data[localIndex] = value;
+        page.BitMap[localIndex] = true;
+        pageBuffer.MarkPageModified(pageIndex);
+    }
+
+    /// <summary>
+    /// Gets the value at the specified index in the virtual memory.
+    /// </summary>
+    /// <param name="index">The index from which to get the value.</param>
+    /// <returns>The value at the specified index.</returns>
+    /// <exception cref="IndexOutOfRangeException">Thrown when the index is out of range.</exception>
+    /// <exception cref="InvalidOperationException">Thrown when the element is not initialized.</exception>
+    public int Get(int index)
+    {
+        if (index < 0)
+        {
+            throw new IndexOutOfRangeException("Индекс вне границ массива");
+        }
+
+        var pageIndex = index / ElementsPerPage;
+        var localIndex = index % ElementsPerPage;
+        var page = pageBuffer.GetPage(pageIndex);
+
+        if (localIndex >= page.BitMap.Length)
+        {
+            throw new IndexOutOfRangeException("Локальный индекс выходит за границы битовой карты страницы");
+        }
+
+        if (!page.BitMap[localIndex])
+        {
+            throw new InvalidOperationException("Элемент не инициализирован");
+        }
+
+        return page.Data[localIndex];
+    }
+
+    /// <summary>
+    /// Disposes the virtual memory and releases all resources.
+    /// </summary>
+    public void Dispose()
+    {
+        pageBuffer.Dispose();
+        GC.SuppressFinalize(this);
+    }
+}
\ No newline at end of file
diff --git a/VM/Domain/Page.cs b/VM/Domain/Page.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9deef0e51212e1fbc180a0748e6b53048556223e
--- /dev/null
+++ b/VM/Domain/Page.cs
@@ -0,0 +1,28 @@
+
+namespace VM.Domain;
+
+using System;
+using System.Collections;
+
+public class Page: IPage
+{
+    public int PageIndex { get; }
+    public DateTime AccessTime { get; set; }
+    public bool IsModified { get; set; }
+    public BitArray BitMap { get; }
+    public int[] Data { get; }
+
+    public Page(int pageIndex, BitArray bitMap, int[] data)
+    {
+        if (bitMap is not { Length: 128 })
+            throw new ArgumentException("BitMap должен содержать 128 бит", nameof(bitMap));
+        if (data is not { Length: 128 })
+            throw new ArgumentException("Data должен содержать 128 элементов", nameof(data));
+
+        PageIndex = pageIndex;
+        AccessTime = DateTime.Now;
+        IsModified = false;
+        BitMap = bitMap;
+        Data = data;
+    }
+}
\ No newline at end of file
diff --git a/VM/Domain/PageBuffer.cs b/VM/Domain/PageBuffer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f8d46c44c6da97835634c9473fa7cc1ec8cee4bf
--- /dev/null
+++ b/VM/Domain/PageBuffer.cs
@@ -0,0 +1,66 @@
+namespace VM.Domain;
+
+public class PageBuffer(
+    ISwapFile swapFile,
+    IDateTimeService dateTimeService,
+    int maxPages = PageBuffer.DefaultMaxPagesInMemory)
+    : IPageBuffer
+{
+    private readonly List<IPage> _pages = [];
+
+    public IPage GetPage(int pageIndex)
+    {
+        var page = _pages.FirstOrDefault(p => p.PageIndex == pageIndex);
+        if (page != null)
+        {
+            page.AccessTime = dateTimeService.CurrentDateTime();
+            return page;
+        }
+
+        if (_pages.Count >= maxPages)
+            ReplaceOldestPage();
+
+        page = swapFile.LoadPage(pageIndex);
+        page.AccessTime = dateTimeService.CurrentDateTime();
+        _pages.Add(page);
+        return page;
+    }
+
+    public void MarkPageModified(int pageIndex)
+    {
+        var page = _pages.FirstOrDefault(p => p.PageIndex == pageIndex) ?? GetPage(pageIndex);
+        page.IsModified = true;
+        page.AccessTime = dateTimeService.CurrentDateTime();
+    }
+
+    private void ReplaceOldestPage()
+    {
+        var oldestPage = _pages.MinBy(p => p.AccessTime);
+        if (oldestPage == null) return;
+
+        if (oldestPage.IsModified)
+        {
+            swapFile.SavePage(oldestPage);
+        }
+
+        _pages.Remove(oldestPage);
+    }
+
+    private void SaveAllPages()
+    {
+        foreach (var page in _pages)
+        {
+            swapFile.SavePage(page);
+        }
+        _pages.Clear();
+    }
+
+    private const int DefaultMaxPagesInMemory = 3;
+
+    public void Dispose()
+    {
+        SaveAllPages();
+        swapFile.Dispose();
+        GC.SuppressFinalize(this);
+    }
+}
\ No newline at end of file
diff --git a/VM/Domain/SwapFile.cs b/VM/Domain/SwapFile.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f5857ef23dd15f68033856263243772190de09b6
--- /dev/null
+++ b/VM/Domain/SwapFile.cs
@@ -0,0 +1,104 @@
+using System.Collections;
+
+namespace VM.Domain;
+
+/// <summary>
+/// Represents a swap file used for managing virtual memory pages.
+/// </summary>
+public class SwapFile : ISwapFile
+{
+    private readonly FileStream _fs;
+    private readonly BinaryWriter _writer;
+    private readonly BinaryReader _reader;
+
+    private const int PageSize = 512;
+    private const int ElementsPerPage = 128;
+    private const int BitMapSize = ElementsPerPage / 8;
+    private const int StartOffset = 2;
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="SwapFile"/> class.
+    /// </summary>
+    /// <param name="fileName">The name of the swap file.</param>
+    /// <param name="size">The size of the swap file.</param>
+    public SwapFile(string fileName, long size)
+    {
+        _fs = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite);
+        _writer = new BinaryWriter(_fs);
+        _reader = new BinaryReader(_fs);
+
+        InitializeFile(size);
+    }
+
+    /// <summary>
+    /// Initializes the swap file with the specified size.
+    /// </summary>
+    /// <param name="size">The size of the swap file.</param>
+    private void InitializeFile(long size)
+    {
+        _writer.Write("VM"u8.ToArray());
+
+        var pageCount = (size * sizeof(int) + PageSize - 1) / PageSize;
+        for (int i = 0; i < pageCount; i++)
+        {
+            _writer.Write(new byte[BitMapSize]);
+            _writer.Write(new byte[PageSize]);
+        }
+
+        _writer.Flush();
+    }
+
+    /// <summary>
+    /// Loads the page at the specified index.
+    /// </summary>
+    /// <param name="pageIndex">The index of the page to load.</param>
+    /// <returns>The loaded page.</returns>
+    /// <exception cref="InvalidOperationException">Thrown when the requested page is out of file bounds.</exception>
+    public IPage LoadPage(int pageIndex)
+    {
+        if (_fs.Length < StartOffset + (pageIndex + 1) * PageSize)
+            throw new InvalidOperationException("Запрашиваемая страница выходит за границы файла.");
+
+        _fs.Seek(StartOffset + pageIndex * PageSize, SeekOrigin.Begin);
+        var bitMapBytes = _reader.ReadBytes(BitMapSize);
+        var bitmap = new BitArray(bitMapBytes);
+        var data = new int[ElementsPerPage];
+
+        for (int i = 0; i < ElementsPerPage; i++)
+        {
+            data[i] = _reader.ReadInt32();
+        }
+
+        return new Page(pageIndex, bitmap, data);
+    }
+
+    /// <summary>
+    /// Saves the specified page to the swap file.
+    /// </summary>
+    /// <param name="page">The page to save.</param>
+    public void SavePage(IPage page)
+    {
+        _fs.Seek(StartOffset + page.PageIndex * PageSize, SeekOrigin.Begin);
+        var bitMapBytes = new byte[BitMapSize];
+        page.BitMap.CopyTo(bitMapBytes, 0);
+        _writer.Write(bitMapBytes);
+
+        for (var i = 0; i < ElementsPerPage; i++)
+        {
+            _writer.Write(page.Data[i]);
+        }
+
+        _writer.Flush();
+    }
+
+    /// <summary>
+    /// Disposes the resources used by the swap file.
+    /// </summary>
+    public void Dispose()
+    {
+        _writer.Dispose();
+        _reader.Dispose();
+        _fs.Dispose();
+        GC.SuppressFinalize(this);
+    }
+}
\ No newline at end of file
diff --git a/VM/Domain/SystemDateTimeService.cs b/VM/Domain/SystemDateTimeService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..641876c3ab120099a18fb02da848f95a1b3d59f4
--- /dev/null
+++ b/VM/Domain/SystemDateTimeService.cs
@@ -0,0 +1,9 @@
+namespace VM.Domain;
+
+public class SystemDateTimeService : IDateTimeService
+{
+    public DateTime CurrentDateTime()
+    {
+        return DateTime.Now;
+    }
+}
\ No newline at end of file
diff --git a/VM/Domain/VarcharVirtualMemory.cs b/VM/Domain/VarcharVirtualMemory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..704ae3f64c4c6a847a44bd7f1c05f2ef63914c5d
--- /dev/null
+++ b/VM/Domain/VarcharVirtualMemory.cs
@@ -0,0 +1,104 @@
+using System.Text;
+
+namespace VM.Domain;
+
+/// <summary>
+/// Represents a virtual memory for storing variable-length strings.
+/// </summary>
+public class VarcharVirtualMemory : IVirtualMemory<string>
+{
+    private const int ElementsPerPage = 128;
+
+    private readonly int _maxStringSize;
+    private readonly ISwapFile _swapFile;
+    private readonly FileStream _dataFile;
+    private readonly int _size;
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="VarcharVirtualMemory"/> class.
+    /// </summary>
+    /// <param name="swapFile">The swap file used to manage pages of memory.</param>
+    /// <param name="dataFileName">The name of the data file used to store string values.</param>
+    /// <param name="maxStringSize">The maximum size of the strings to be stored.</param>
+    public VarcharVirtualMemory(ISwapFile swapFile, string dataFileName, int maxStringSize, int size)
+    {
+        _maxStringSize = maxStringSize;
+        _swapFile = swapFile;
+        _dataFile = new FileStream(dataFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
+        _size = size;
+    }
+
+    /// <summary>
+    /// Sets the string value at the specified index in the virtual memory.
+    /// </summary>
+    /// <param name="index">The index at which to set the value.</param>
+    /// <param name="value">The string value to set.</param>
+    /// <exception cref="IndexOutOfRangeException">Thrown when the index is out of range.</exception>
+    /// <exception cref="ArgumentException">Thrown when the string exceeds the maximum size.</exception>
+    public void Set(int index, string value)
+    {
+        if (index < 0 || index >= _size)
+            throw new IndexOutOfRangeException("Индекс вне границ массива");
+
+        if (value.Length > _maxStringSize)
+            throw new ArgumentException($"Строка превышает максимальный размер {_maxStringSize} символов");
+
+        var pageIndex = index / ElementsPerPage;
+        var localIndex = index % ElementsPerPage;
+
+        var page = _swapFile.LoadPage(pageIndex);
+        long position;
+
+        using (var writer = new BinaryWriter(_dataFile, Encoding.UTF8, true))
+        {
+            _dataFile.Seek(0, SeekOrigin.End);
+            position = _dataFile.Position;
+
+            writer.Write(value.Length);
+            writer.Write(Encoding.UTF8.GetBytes(value));
+        }
+
+        page.Data[localIndex] = (int)position;
+        page.BitMap[localIndex] = true;
+
+        _swapFile.SavePage(page);
+    }
+
+    /// <summary>
+    /// Gets the string value at the specified index in the virtual memory.
+    /// </summary>
+    /// <param name="index">The index from which to get the value.</param>
+    /// <returns>The string value at the specified index.</returns>
+    /// <exception cref="IndexOutOfRangeException">Thrown when the index is out of range.</exception>
+    /// <exception cref="InvalidOperationException">Thrown when the element is not initialized.</exception>
+    public string Get(int index)
+    {
+        if (index < 0)
+            throw new IndexOutOfRangeException("Индекс вне границ массива");
+
+        var pageIndex = index / ElementsPerPage;
+        var localIndex = index % ElementsPerPage;
+        var page = _swapFile.LoadPage(pageIndex);
+
+        if (!page.BitMap[localIndex])
+            throw new InvalidOperationException("Элемент не инициализирован");
+
+        long position = page.Data[localIndex];
+
+        using var reader = new BinaryReader(_dataFile, Encoding.UTF8, true);
+        _dataFile.Seek(position, SeekOrigin.Begin);
+        var length = reader.ReadInt32();
+        var bytes = reader.ReadBytes(length);
+        return Encoding.UTF8.GetString(bytes);
+    }
+
+    /// <summary>
+    /// Disposes the resources used by the virtual memory.
+    /// </summary>
+    public void Dispose()
+    {
+        _swapFile.Dispose();
+        _dataFile.Dispose();
+        GC.SuppressFinalize(this);
+    }
+}
\ No newline at end of file
diff --git a/VM/VM.csproj b/VM/VM.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..31d2e9283f7c42ff4b732cd409ebc68a5eee5b89
--- /dev/null
+++ b/VM/VM.csproj
@@ -0,0 +1,13 @@
+п»ї<Project Sdk="Microsoft.NET.Sdk">
+
+    <PropertyGroup>
+        <TargetFramework>net9.0</TargetFramework>
+        <ImplicitUsings>enable</ImplicitUsings>
+        <Nullable>enable</Nullable>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2" />
+    </ItemGroup>
+
+</Project>