diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..e7e7cb3
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,6 @@
+image: Visual Studio 2019
+
+build_script:
+ - For /R %%I in (*.sln) do dotnet test %%I
+
+test: off
\ No newline at end of file
diff --git a/hw2LZW/hw2LZW.sln b/hw2LZW/hw2LZW.sln
new file mode 100644
index 0000000..884139e
--- /dev/null
+++ b/hw2LZW/hw2LZW.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31005.135
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hw2LZW", "hw2LZW\Hw2LZW.csproj", "{956FF906-65B8-45A7-AEEC-0C4F4D47EF5D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "hw2Lzw.Test", "hw2LzwTest\hw2Lzw.Test.csproj", "{705F21DF-850F-439F-BF37-F0F8EF554073}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {956FF906-65B8-45A7-AEEC-0C4F4D47EF5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {956FF906-65B8-45A7-AEEC-0C4F4D47EF5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {956FF906-65B8-45A7-AEEC-0C4F4D47EF5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {956FF906-65B8-45A7-AEEC-0C4F4D47EF5D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {705F21DF-850F-439F-BF37-F0F8EF554073}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {705F21DF-850F-439F-BF37-F0F8EF554073}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {705F21DF-850F-439F-BF37-F0F8EF554073}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {705F21DF-850F-439F-BF37-F0F8EF554073}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {DB7EE293-FCD3-4437-92C9-C3ABFADE5DE7}
+ EndGlobalSection
+EndGlobal
diff --git a/hw2LZW/hw2LZW/LZW.cs b/hw2LZW/hw2LZW/LZW.cs
new file mode 100644
index 0000000..0f36315
--- /dev/null
+++ b/hw2LZW/hw2LZW/LZW.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections.Generic;
+using System.Collections;
+using System.IO;
+
+namespace Hw2LZW
+{
+ ///
+ /// класс для сжатия и разжатия
+ ///
+ public static class LZW
+ {
+ private static int GetCountOfBytes(byte[] array)
+ {
+ for (int i = array.Length - 1; i >= 0; i--)
+ {
+ if (array[i] != 0)
+ {
+ return i + 1;
+ }
+ }
+ return 1;
+ }
+
+ ///
+ /// функция сжатия файла
+ ///
+ /// путь до файла, который будем сжимать
+ public static void Compress(string pathFile)
+ {
+ using var file = new FileStream(pathFile, FileMode.Open);
+ var trie = new Trie();
+ var codes = new Queue();
+ for (int i = 0; i < file.Length; ++i)
+ {
+ var byter = (byte)file.ReadByte();
+ var codeOfBytes = trie.IsAdd(byter);
+ if (codeOfBytes != -1)
+ {
+ codes.Enqueue(codeOfBytes);
+ trie.IsAdd(byter);
+ }
+ }
+ codes.Enqueue(trie.GetCode());
+ var countOfBytes = GetCountOfBytes(BitConverter.GetBytes(trie.CountCodes));
+ using var fileZipped = new FileStream(pathFile + ".zipped", FileMode.CreateNew);
+ fileZipped.WriteByte((byte)countOfBytes);
+ var size = codes.Count;
+ for (int i = 0; i < size; i++)
+ {
+ var helpArray = BitConverter.GetBytes(codes.Dequeue());
+ fileZipped.Write(helpArray, 0, countOfBytes);
+ }
+ }
+
+ private static Hashtable InitializeHashtable()
+ {
+ var hashtable = new Hashtable();
+ for (int i = 0; i < 256; i++)
+ {
+ hashtable.Add(i, new byte[] { (byte)i });
+ }
+ return hashtable;
+ }
+
+ private static void AddLastSymbol(int code, Hashtable hashtable)
+ {
+ var bytes = (byte[])hashtable[code];
+ var previous = (byte[])hashtable[hashtable.Count - 1];
+ previous[previous.Length - 1] = bytes[0];
+ }
+
+ ///
+ /// функция для разжатия
+ ///
+ /// путь до сжатого файла
+ public static void Decompress(string pathFile)
+ {
+ var hashtable = InitializeHashtable();
+ var codes = hashtable.Count;
+ using var fileZipped = new FileStream(pathFile, FileMode.Open);
+ using var file = new FileStream(pathFile.Substring(0, pathFile.Length - 7), FileMode.OpenOrCreate);
+ int maxLength = fileZipped.ReadByte();
+ for (int i = 0; i < fileZipped.Length - 1; i += maxLength)
+ {
+ var codeInBytes = new byte[4];
+ for (int j = 0; j < maxLength; ++j)
+ {
+ codeInBytes[j] = (byte)fileZipped.ReadByte();
+ }
+ var code = BitConverter.ToInt32(codeInBytes, 0);
+ if (i != 0)
+ {
+ AddLastSymbol(code, hashtable);
+ }
+ var bytesArray = (byte[])hashtable[code];
+ var copyBytesArray = new byte[bytesArray.Length + 1];
+ Array.Copy(bytesArray, copyBytesArray, bytesArray.Length);
+ hashtable.Add(codes, copyBytesArray);
+ codes++;
+ file.Write(bytesArray);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/hw2LZW/hw2LZW/Program.cs b/hw2LZW/hw2LZW/Program.cs
new file mode 100644
index 0000000..2bb683e
--- /dev/null
+++ b/hw2LZW/hw2LZW/Program.cs
@@ -0,0 +1,34 @@
+using System;
+using System.IO;
+
+namespace Hw2LZW
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ if (args.Length != 2)
+ {
+ Console.WriteLine("Ошибка ввода!");
+ return;
+ }
+ if (args[1] == "-c")
+ {
+ LZW.Compress(args[0]);
+ var compressedFileSize = new FileInfo(args[0]);
+ var decompressedFileSize = new FileInfo(args[0] + ".zipped");
+ Console.WriteLine($"Коэффициент сжатия: x {(double)compressedFileSize.Length / decompressedFileSize.Length}");
+ }
+ else if (args[1] == "-u")
+ {
+ LZW.Decompress(args[0]);
+ Console.WriteLine("Файл разжат!");
+ }
+ else
+ {
+ Console.WriteLine("Ошибка ввода!");
+ return;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/hw2LZW/hw2LZW/Trie.cs b/hw2LZW/hw2LZW/Trie.cs
new file mode 100644
index 0000000..11c3488
--- /dev/null
+++ b/hw2LZW/hw2LZW/Trie.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+
+namespace Hw2LZW
+{
+ ///
+ /// вспомогательный класс для реализация Lzw
+ ///
+ public class Trie
+ {
+ private class Node
+ {
+ public byte Bytes { get; }
+
+ public bool IsUsed { get; set; }
+
+ public int IdByte;
+
+ public int CodeBytes { get; set; }
+
+ public Dictionary Sons;
+
+ public Node(byte bytes, int codeByte, bool isUsed)
+ {
+ IsUsed = isUsed;
+ Bytes = bytes;
+ IdByte = codeByte;
+ Sons = new Dictionary();
+ }
+
+ public Node IsFind(byte value)
+ => Sons.TryGetValue(value, out Node node) ? node : null;
+ }
+
+ private Node root = new Node(0, 0, false);
+
+ private Node runner;
+
+ public Trie()
+ {
+ for (int i = 0; i < 256; ++i)
+ {
+ InitRoot((byte)i, i);
+ }
+ runner = root;
+ }
+
+ public int CountCodes { get; set; }
+
+ private void InitRoot(byte idSymbol, int index)
+ {
+
+ var son = new Node(idSymbol, index, false);
+ root.Sons.Add(idSymbol, son);
+ son.CodeBytes = CountCodes;
+ CountCodes++;
+ }
+
+ private bool CheckAdd(byte value, Node node)
+ => node.IsFind(value) == null;
+
+ public int LastCode { get; set; }
+
+ ///
+ /// функция добавления
+ ///
+ /// байт, который хотим добавить
+ /// если такой байт уже есть, то вернем "-1"
+ public int IsAdd(byte value)
+ {
+ if (runner == root)
+ {
+ var check = runner.Sons[value];
+ if (!check.IsUsed)
+ {
+ check.IsUsed = true;
+ runner = runner.Sons[value];
+ LastCode = runner.Bytes;
+ return -1;
+ }
+ }
+ var isCheck = CheckAdd(value, runner);
+ if (isCheck)
+ {
+ var son = new Node(value, CountCodes, true);
+ son.CodeBytes = CountCodes;
+ CountCodes++;
+ runner.Sons.Add(value, son);
+ runner = root;
+ return LastCode;
+ }
+ else
+ {
+ runner = runner.Sons[value];
+ LastCode = runner.CodeBytes;
+ return -1;
+ }
+ }
+
+ ///
+ /// функция для возврата кода у узла
+ ///
+ /// возвращается код узла
+ public int GetCode()
+ => runner.Bytes;
+ }
+}
\ No newline at end of file
diff --git a/hw2LZW/hw2LZW/hw2LZW.csproj b/hw2LZW/hw2LZW/hw2LZW.csproj
new file mode 100644
index 0000000..c73e0d1
--- /dev/null
+++ b/hw2LZW/hw2LZW/hw2LZW.csproj
@@ -0,0 +1,8 @@
+
+
+
+ Exe
+ netcoreapp3.1
+
+
+
diff --git a/hw2LZW/hw2LzwTest/LZWTest.cs b/hw2LZW/hw2LzwTest/LZWTest.cs
new file mode 100644
index 0000000..3ab34f1
--- /dev/null
+++ b/hw2LZW/hw2LzwTest/LZWTest.cs
@@ -0,0 +1,53 @@
+using NUnit.Framework;
+using System.IO;
+
+namespace hw2LzwTest
+{
+ [TestFixture]
+ public class Tests
+ {
+ private bool Compare(string path1, string path2)
+ {
+ using FileStream file1 = File.OpenRead(path1);
+ using FileStream file2 = File.OpenRead(path2);
+ if (file1.Length != file2.Length)
+ {
+ return false;
+ }
+ for (int i = 0; i < file1.Length; ++i)
+ {
+ if (file1.ReadByte() != file2.ReadByte())
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ [TestCase]
+ public void LZWWithTxt()
+ {
+ string path1 = "..\\..\\..\\TestTxt.txt";
+ string path2 = "..\\..\\..\\TestTxtCopy.txt";
+ File.Copy(path1, path2);
+ Hw2LZW.LZW.Compress(path1);
+ Hw2LZW.LZW.Decompress(path1 + ".zipped");
+ File.Delete(path1 + ".zipped");
+ Assert.IsTrue(Compare(path1, path2));
+ File.Delete(path2);
+ }
+
+ [TestCase]
+ public void LZWWithImg()
+ {
+ string path1 = "..\\..\\..\\TestImg.jpg";
+ string path2 = "..\\..\\..\\TestImgCopy.jpg";
+ File.Copy(path1, path2);
+ Hw2LZW.LZW.Compress(path1);
+ Hw2LZW.LZW.Decompress(path1 + ".zipped");
+ File.Delete(path1 + ".zipped");
+ Assert.IsTrue(Compare(path1, path2));
+ File.Delete(path2);
+ }
+ }
+}
\ No newline at end of file
diff --git a/hw2LZW/hw2LzwTest/TestImg.jpg b/hw2LZW/hw2LzwTest/TestImg.jpg
new file mode 100644
index 0000000..e27885f
Binary files /dev/null and b/hw2LZW/hw2LzwTest/TestImg.jpg differ
diff --git a/hw2LZW/hw2LzwTest/TestTxt.txt b/hw2LZW/hw2LzwTest/TestTxt.txt
new file mode 100644
index 0000000..7801a8a
--- /dev/null
+++ b/hw2LZW/hw2LzwTest/TestTxt.txt
@@ -0,0 +1,3 @@
+sleep and code
+eat and code
+walk and coee
\ No newline at end of file
diff --git a/hw2LZW/hw2LzwTest/hw2Lzw.Test.csproj b/hw2LZW/hw2LzwTest/hw2Lzw.Test.csproj
new file mode 100644
index 0000000..1ff4cb0
--- /dev/null
+++ b/hw2LZW/hw2LzwTest/hw2Lzw.Test.csproj
@@ -0,0 +1,19 @@
+
+
+
+ netcoreapp3.1
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+