diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..176a458
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* text=auto
diff --git a/.gitignore b/.gitignore
index 42d3208..504dc97 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,17 +1,9 @@
-## .gitignore
-#.gitignore
-
-###
-## *.html
-###
-## !special.html
-### ..
-## *.[ao]
-
-
-*.suo
-*.user
-.vs/
-bin/
-obj/
-packages/
\ No newline at end of file
+*.suo
+*.user
+.vs/
+bin/
+obj/
+packages/
+
+# Terminal Paste Image folder
+.cp-images/
diff --git a/README.md b/README.md
index 1036790..205754e 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,23 @@
# Тестовое задание.
-Доброго дня.
+
+Доброго дня.
Данный репозиторий представляет из себя тестовое задание для выполнения перед собеседованием на вакансию разработчика C# в компанию Катрен.
-Репозиторий уже содержит основные классы и методы для последующей разработки.
-Большая часть уже описаных методов - _заглушки_, требующие реализации.
+Репозиторий уже содержит основные классы и методы для последующей разработки.
+Большая часть уже описаных методов - _заглушки_, требующие реализации.
-Все методы/классы документированы и описывают своё предназначение и требуемое поведение.
-Таким образом, чтобы понять что именно данный метод должен делать - достаточно внимательно прочитать его документацию.
+Все методы/классы документированы и описывают своё предназначение и требуемое поведение.
+Таким образом, чтобы понять что именно данный метод должен делать - достаточно внимательно прочитать его документацию.
-Все места, требующие реализации, помечены _TODO_ маркером. Всего таких мест 9 шт.
-Все _TODO_ маркеры можно найти нажатием _"Ctrl+W, T"_ (Visual Studio 2017) или любым другим удобным для Вас способом.
+Все места, требующие реализации, помечены _TODO_ маркером. Всего таких мест 9 шт.
+Все _TODO_ маркеры можно найти нажатием _"Ctrl+W, T"_ (Visual Studio 2017) или любым другим удобным для Вас способом.
-Исходный код содержит ошибки/недоработки, которые необходимо исправить каким-либо способом процессе разработки.
+Исходный код содержит ошибки/недоработки, которые необходимо исправить каким-либо способом процессе разработки.
-В рамках разработки не запрещается как-либо модифицировать уже существующий код.
-А именно допускается: создание/удаление/модификация методов/классов/структур и т.д., если этого требует ваша реализация.
+В рамках разработки не запрещается как-либо модифицировать уже существующий код.
+А именно допускается: создание/удаление/модификация методов/классов/структур и т.д., если этого требует ваша реализация.
-__Для разработки настоятельно рекомендуется сделать Fork данного проекта.
-И по готовности результат отдать на ревью методом Pull Request'a.__
+**Для разработки настоятельно рекомендуется сделать Fork данного проекта.
+И по готовности результат отдать на ревью методом Pull Request'a.**
-Если данный способ по каким-то причинам Вам не представляется реализуемым, можете выслать результат в виде архива на почту кадровому агенту.
+Если данный способ по каким-то причинам Вам не представляется реализуемым, можете выслать результат в виде архива на почту кадровому агенту.
diff --git a/TestTask/LetterStats.cs b/TestTask/CharStats.cs
similarity index 79%
rename from TestTask/LetterStats.cs
rename to TestTask/CharStats.cs
index aa10728..f28093d 100644
--- a/TestTask/LetterStats.cs
+++ b/TestTask/CharStats.cs
@@ -1,18 +1,18 @@
-namespace TestTask
-{
- ///
- /// Статистика вхождения буквы/пары букв
- ///
- public struct LetterStats
- {
- ///
- /// Буква/Пара букв для учёта статистики.
- ///
- public string Letter;
-
- ///
- /// Кол-во вхождений буквы/пары.
- ///
- public int Count;
- }
-}
+namespace TestTask
+{
+ ///
+ /// Статистика вхождения буквы/пары букв
+ ///
+ public class CharStats
+ {
+ ///
+ /// Буква/Пара букв для учёта статистики.
+ ///
+ public string Char;
+
+ ///
+ /// Кол-во вхождений буквы/пары.
+ ///
+ public int Count;
+ }
+}
diff --git a/TestTask/CharType.cs b/TestTask/CharType.cs
index 899564d..0d92220 100644
--- a/TestTask/CharType.cs
+++ b/TestTask/CharType.cs
@@ -1,18 +1,30 @@
-namespace TestTask
-{
- ///
- /// Тип букв
- ///
- public enum CharType
- {
- ///
- /// Гласные
- ///
- Vowel,
-
- ///
- /// Согласные
- ///
- Consonants
- }
-}
+namespace TestTask
+{
+ ///
+ /// Тип букв
+ ///
+ public enum CharType
+ {
+ ///
+ /// Гласные
+ ///
+ Vowel,
+
+ ///
+ /// Согласные
+ ///
+ Consonants
+ }
+
+ ///
+ /// Вспомогательный класс для классификации букв по типу.
+ ///
+ public static class CharTypeHelper
+ {
+ private const string RussianVowels = "аеёиоуыэюя";
+ // TODO: добавить латинские гласные при необходимости: "aeiou"
+
+ public static bool IsVowel(char c) =>
+ RussianVowels.Contains(char.ToLower(c));
+ }
+}
diff --git a/TestTask/IReadOnlyStream.cs b/TestTask/IReadOnlyStream.cs
index 6946745..e615414 100644
--- a/TestTask/IReadOnlyStream.cs
+++ b/TestTask/IReadOnlyStream.cs
@@ -1,16 +1,17 @@
-namespace TestTask
-{
- ///
- /// Интерфейс для работы с файлом в сильно урезаном виде.
- /// Умеет всего 2 вещи: прочитать символ, и перемотать стрим на начало.
- ///
- internal interface IReadOnlyStream
- {
- // TODO : Необходимо доработать данный интерфейс для обеспечения гарантированного закрытия файла, по окончанию работы с таковым!
- char ReadNextChar();
-
- void ResetPositionToStart();
-
- bool IsEof { get; }
- }
-}
+using System;
+
+namespace TestTask
+{
+ ///
+ /// Интерфейс для работы с файлом в сильно урезаном виде.
+ /// Умеет всего 2 вещи: прочитать символ, и перемотать стрим на начало.
+ ///
+ internal interface IReadOnlyStream : IDisposable
+ {
+ char ReadNextChar();
+
+ void ResetPositionToStart();
+
+ bool IsEof { get; }
+ }
+}
diff --git a/TestTask/Program.cs b/TestTask/Program.cs
index fdf048e..f335f3d 100644
--- a/TestTask/Program.cs
+++ b/TestTask/Program.cs
@@ -1,129 +1,185 @@
-using System;
-using System.Collections.Generic;
-
-namespace TestTask
-{
- public class Program
- {
-
- ///
- /// Программа принимает на входе 2 пути до файлов.
- /// Анализирует в первом файле кол-во вхождений каждой буквы (регистрозависимо). Например А, б, Б, Г и т.д.
- /// Анализирует во втором файле кол-во вхождений парных букв (не регистрозависимо). Например АА, Оо, еЕ, тт и т.д.
- /// По окончанию работы - выводит данную статистику на экран.
- ///
- /// Первый параметр - путь до первого файла.
- /// Второй параметр - путь до второго файла.
- static void Main(string[] args)
- {
- IReadOnlyStream inputStream1 = GetInputStream(args[0]);
- IReadOnlyStream inputStream2 = GetInputStream(args[1]);
-
- IList singleLetterStats = FillSingleLetterStats(inputStream1);
- IList doubleLetterStats = FillDoubleLetterStats(inputStream2);
-
- RemoveCharStatsByType(singleLetterStats, CharType.Vowel);
- RemoveCharStatsByType(doubleLetterStats, CharType.Consonants);
-
- PrintStatistic(singleLetterStats);
- PrintStatistic(doubleLetterStats);
-
- // TODO : Необжодимо дождаться нажатия клавиши, прежде чем завершать выполнение программы.
- }
-
- ///
- /// Ф-ция возвращает экземпляр потока с уже загруженным файлом для последующего посимвольного чтения.
- ///
- /// Полный путь до файла для чтения
- /// Поток для последующего чтения.
- private static IReadOnlyStream GetInputStream(string fileFullPath)
- {
- return new ReadOnlyStream(fileFullPath);
- }
-
- ///
- /// Ф-ция считывающая из входящего потока все буквы, и возвращающая коллекцию статистик вхождения каждой буквы.
- /// Статистика РЕГИСТРОЗАВИСИМАЯ!
- ///
- /// Стрим для считывания символов для последующего анализа
- /// Коллекция статистик по каждой букве, что была прочитана из стрима.
- private static IList FillSingleLetterStats(IReadOnlyStream stream)
- {
- stream.ResetPositionToStart();
- while (!stream.IsEof)
- {
- char c = stream.ReadNextChar();
- // TODO : заполнять статистику с использованием метода IncStatistic. Учёт букв - регистрозависимый.
- }
-
- //return ???;
-
- throw new NotImplementedException();
- }
-
- ///
- /// Ф-ция считывающая из входящего потока все буквы, и возвращающая коллекцию статистик вхождения парных букв.
- /// В статистику должны попадать только пары из одинаковых букв, например АА, СС, УУ, ЕЕ и т.д.
- /// Статистика - НЕ регистрозависимая!
- ///
- /// Стрим для считывания символов для последующего анализа
- /// Коллекция статистик по каждой букве, что была прочитана из стрима.
- private static IList FillDoubleLetterStats(IReadOnlyStream stream)
- {
- stream.ResetPositionToStart();
- while (!stream.IsEof)
- {
- char c = stream.ReadNextChar();
- // TODO : заполнять статистику с использованием метода IncStatistic. Учёт букв - НЕ регистрозависимый.
- }
-
- //return ???;
-
- throw new NotImplementedException();
- }
-
- ///
- /// Ф-ция перебирает все найденные буквы/парные буквы, содержащие в себе только гласные или согласные буквы.
- /// (Тип букв для перебора определяется параметром charType)
- /// Все найденные буквы/пары соответствующие параметру поиска - удаляются из переданной коллекции статистик.
- ///
- /// Коллекция со статистиками вхождения букв/пар
- /// Тип букв для анализа
- private static void RemoveCharStatsByType(IList letters, CharType charType)
- {
- // TODO : Удалить статистику по запрошенному типу букв.
- switch (charType)
- {
- case CharType.Consonants:
- break;
- case CharType.Vowel:
- break;
- }
-
- }
-
- ///
- /// Ф-ция выводит на экран полученную статистику в формате "{Буква} : {Кол-во}"
- /// Каждая буква - с новой строки.
- /// Выводить на экран необходимо предварительно отсортировав набор по алфавиту.
- /// В конце отдельная строчка с ИТОГО, содержащая в себе общее кол-во найденных букв/пар
- ///
- /// Коллекция со статистикой
- private static void PrintStatistic(IEnumerable letters)
- {
- // TODO : Выводить на экран статистику. Выводить предварительно отсортировав по алфавиту!
- throw new NotImplementedException();
- }
-
- ///
- /// Метод увеличивает счётчик вхождений по переданной структуре.
- ///
- ///
- private static void IncStatistic(LetterStats letterStats)
- {
- letterStats.Count++;
- }
-
-
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace TestTask
+{
+ /*
+ NOTE: В production-коде методы стоило бы вынести в отдельные классы по ответственностям:
+ StatisticsCollector (CollectSingle/DoubleCharStats), StatisticsFilter (RemoveCharStatsByType),
+ StatisticsPrinter (PrintStatistic)
+ */
+ public class Program
+ {
+
+ ///
+ /// Программа принимает на входе 2 пути до файлов.
+ /// Анализирует в первом файле кол-во вхождений каждой буквы (регистрозависимо). Например А, б, Б, Г и т.д.
+ /// Анализирует во втором файле кол-во вхождений парных букв (не регистрозависимо). Например АА, Оо, еЕ, тт и т.д.
+ /// По окончанию работы - выводит данную статистику на экран.
+ ///
+ /// Массив аргументов командной строки:
+ /// args[0] - путь до первого файла,
+ /// args[1] - путь до второго файла.
+ static void Main(string[] args)
+ {
+ IReadOnlyStream singleCharStream = GetInputStream(args[0]);
+ IReadOnlyStream doubleCharStream = GetInputStream(args[1]);
+
+ IList singleCharStats = CollectSingleCharStats(singleCharStream);
+ IList doubleCharStats = CollectDoubleCharStats(doubleCharStream);
+
+ RemoveCharStatsByType(singleCharStats, CharType.Vowel);
+ RemoveCharStatsByType(doubleCharStats, CharType.Consonants);
+
+ PrintStatistic(singleCharStats);
+ PrintStatistic(doubleCharStats);
+
+ Console.ReadKey();
+ }
+
+ ///
+ /// Ф-ция возвращает экземпляр потока с уже загруженным файлом для последующего посимвольного чтения.
+ ///
+ /// Полный путь до файла для чтения
+ /// Поток для последующего чтения.
+ private static IReadOnlyStream GetInputStream(string fileFullPath)
+ {
+ return new ReadOnlyStream(fileFullPath);
+ }
+
+ ///
+ /// Ф-ция считывающая из входящего потока все буквы, и возвращающая коллекцию статистик вхождения каждой буквы.
+ /// Статистика РЕГИСТРОЗАВИСИМАЯ!
+ ///
+ /// Стрим для считывания символов для последующего анализа
+ /// Коллекция статистик по каждой букве, что была прочитана из стрима.
+ private static IList CollectSingleCharStats(IReadOnlyStream stream)
+ {
+ var stats = new List();
+
+ stream.ResetPositionToStart();
+ while (!stream.IsEof)
+ {
+ char currentChar = stream.ReadNextChar();
+
+ if (!char.IsLetter(currentChar))
+ {
+ continue;
+ }
+
+ var stat = stats.FirstOrDefault(stat => stat.Char == currentChar.ToString());
+
+ if (stat == null)
+ {
+ stats.Add(new CharStats { Char = currentChar.ToString(), Count = 1 });
+ }
+
+ else
+ {
+ IncStatistic(stat);
+ }
+
+ }
+ return stats;
+ }
+
+ ///
+ /// Ф-ция считывающая из входящего потока все буквы, и возвращающая коллекцию статистик вхождения парных букв.
+ /// В статистику должны попадать только пары из одинаковых букв, например АА, СС, УУ, ЕЕ и т.д.
+ /// Статистика - НЕ регистрозависимая!
+ ///
+ /// Стрим для считывания символов для последующего анализа
+ /// Коллекция статистик по каждой букве, что была прочитана из стрима.
+ private static IList CollectDoubleCharStats(IReadOnlyStream stream)
+ {
+ var stats = new List();
+ bool prevWasLetter = false;
+ char prevChar = default;
+
+ stream.ResetPositionToStart();
+ while (!stream.IsEof)
+ {
+ char currentChar = stream.ReadNextChar();
+
+ if (!char.IsLetter(currentChar))
+ {
+ prevWasLetter = false;
+ continue;
+ }
+
+ if (prevWasLetter && char.ToLower(prevChar) == char.ToLower(currentChar))
+ {
+ var pairKey = new string(char.ToLower(currentChar), 2);
+ var stat = stats.FirstOrDefault(stat => stat.Char == pairKey);
+ if (stat == null)
+ {
+ stats.Add(new CharStats { Char = pairKey, Count = 1 });
+ }
+
+ else
+ {
+ IncStatistic(stat);
+ }
+ }
+
+ prevChar = currentChar;
+ prevWasLetter = true;
+ }
+
+ return stats;
+ }
+
+ ///
+ /// Ф-ция перебирает все найденные буквы/парные буквы, содержащие в себе только гласные или согласные буквы.
+ /// (Тип букв для перебора определяется параметром charType)
+ /// Все найденные буквы/пары соответствующие параметру поиска - удаляются из переданной коллекции статистик.
+ ///
+ /// Коллекция со статистиками вхождения букв/пар
+ /// Тип букв для анализа
+ private static void RemoveCharStatsByType(IList stats, CharType charType)
+ {
+ for (int i = stats.Count - 1; i >= 0; i--)
+ {
+ bool isVowel = CharTypeHelper.IsVowel(stats[i].Char[0]);
+
+ bool shouldRemove = charType == CharType.Vowel ? isVowel : !isVowel;
+
+ if (shouldRemove)
+ {
+ stats.RemoveAt(i);
+ }
+ }
+ }
+
+ ///
+ /// Ф-ция выводит на экран полученную статистику в формате "{Буква} : {Кол-во}"
+ /// Каждая буква - с новой строки.
+ /// Выводить на экран необходимо предварительно отсортировав набор по алфавиту.
+ /// В конце отдельная строчка с ИТОГО, содержащая в себе общее кол-во найденных букв/пар
+ ///
+ /// Коллекция со статистикой
+ private static void PrintStatistic(IEnumerable stats)
+ {
+ var sorted = stats.OrderBy(stat => stat.Char);
+ int total = 0;
+
+ foreach (var stat in sorted)
+ {
+ Console.WriteLine($"{stat.Char} : {stat.Count}");
+ total += stat.Count;
+ }
+
+ Console.WriteLine($"ИТОГО : {total}");
+ }
+
+ ///
+ /// Метод увеличивает счётчик вхождений по переданной структуре.
+ ///
+ ///
+ private static void IncStatistic(CharStats charStats)
+ {
+ charStats.Count++;
+ }
+ }
+}
diff --git a/TestTask/Properties/AssemblyInfo.cs b/TestTask/Properties/AssemblyInfo.cs
index aecb854..34d8ed5 100644
--- a/TestTask/Properties/AssemblyInfo.cs
+++ b/TestTask/Properties/AssemblyInfo.cs
@@ -1,36 +1,36 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("TestTask")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("TestTask")]
-[assembly: AssemblyCopyright("Copyright © 2018")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("6e9922f2-af75-4807-b6e4-f74499317c39")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("TestTask")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("TestTask")]
+[assembly: AssemblyCopyright("Copyright © 2018")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("6e9922f2-af75-4807-b6e4-f74499317c39")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/TestTask/ReadOnlyStream.cs b/TestTask/ReadOnlyStream.cs
index a51a61e..13225e7 100644
--- a/TestTask/ReadOnlyStream.cs
+++ b/TestTask/ReadOnlyStream.cs
@@ -1,60 +1,77 @@
-using System;
-using System.IO;
-
-namespace TestTask
-{
- public class ReadOnlyStream : IReadOnlyStream
- {
- private Stream _localStream;
-
- ///
- /// Конструктор класса.
- /// Т.к. происходит прямая работа с файлом, необходимо
- /// обеспечить ГАРАНТИРОВАННОЕ закрытие файла после окончания работы с таковым!
- ///
- /// Полный путь до файла для чтения
- public ReadOnlyStream(string fileFullPath)
- {
- IsEof = true;
-
- // TODO : Заменить на создание реального стрима для чтения файла!
- _localStream = null;
- }
-
- ///
- /// Флаг окончания файла.
- ///
- public bool IsEof
- {
- get; // TODO : Заполнять данный флаг при достижении конца файла/стрима при чтении
- private set;
- }
-
- ///
- /// Ф-ция чтения следующего символа из потока.
- /// Если произведена попытка прочитать символ после достижения конца файла, метод
- /// должен бросать соответствующее исключение
- ///
- /// Считанный символ.
- public char ReadNextChar()
- {
- // TODO : Необходимо считать очередной символ из _localStream
- throw new NotImplementedException();
- }
-
- ///
- /// Сбрасывает текущую позицию потока на начало.
- ///
- public void ResetPositionToStart()
- {
- if (_localStream == null)
- {
- IsEof = true;
- return;
- }
-
- _localStream.Position = 0;
- IsEof = false;
- }
- }
-}
+using System;
+using System.IO;
+
+namespace TestTask
+{
+ public class ReadOnlyStream : IReadOnlyStream
+ {
+ private readonly StreamReader _fileStream;
+
+ ///
+ /// Конструктор класса.
+ /// Класс реализует IDisposable — используйте using/Dispose для гарантированного закрытия файла.
+ ///
+ /// Полный путь до файла для чтения
+ public ReadOnlyStream(string fileFullPath)
+ {
+ _fileStream = new StreamReader(fileFullPath);
+ IsEof = false;
+ }
+
+ ///
+ /// Флаг окончания файла.
+ ///
+ public bool IsEof
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Ф-ция чтения следующего символа из потока.
+ /// Если произведена попытка прочитать символ после достижения конца файла, метод
+ /// бросит соответствующее исключение
+ ///
+ /// Считанный символ.
+ public char ReadNextChar()
+ {
+ if (IsEof)
+ {
+ throw new InvalidOperationException("Stream is already at end of file");
+ }
+
+ var nextChar = (char)_fileStream.Read();
+
+ if (_fileStream.EndOfStream)
+ {
+ IsEof = true;
+ }
+
+ return nextChar;
+ }
+
+ ///
+ /// Сбрасывает текущую позицию потока на начало.
+ ///
+ public void ResetPositionToStart()
+ {
+ if (_fileStream == null)
+ {
+ throw new InvalidOperationException("Stream is not initialized.");
+ }
+
+ _fileStream.BaseStream.Position = 0;
+ _fileStream.DiscardBufferedData();
+ IsEof = false;
+ }
+
+ ///
+ /// Освобождает ресурсы и закрывает файл.
+ ///
+ public void Dispose()
+ {
+ _fileStream.Dispose();
+ GC.SuppressFinalize(this);
+ }
+ }
+}
diff --git a/TestTask/TestTask.csproj b/TestTask/TestTask.csproj
index dc470b0..ebfb651 100644
--- a/TestTask/TestTask.csproj
+++ b/TestTask/TestTask.csproj
@@ -1,53 +1,7 @@
-
-
-
-
- Debug
- AnyCPU
- {6E9922F2-AF75-4807-B6E4-F74499317C39}
- Exe
- TestTask
- TestTask
- v4.6.1
- 512
- true
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+ Exe
+ net8.0
+ false
+
+
diff --git a/TestTask/TestTask.sln b/TestTask/TestTask.sln
index 494bc7e..5725c91 100644
--- a/TestTask/TestTask.sln
+++ b/TestTask/TestTask.sln
@@ -1,25 +1,25 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27428.2011
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestTask", "TestTask.csproj", "{6E9922F2-AF75-4807-B6E4-F74499317C39}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {6E9922F2-AF75-4807-B6E4-F74499317C39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {6E9922F2-AF75-4807-B6E4-F74499317C39}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6E9922F2-AF75-4807-B6E4-F74499317C39}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {6E9922F2-AF75-4807-B6E4-F74499317C39}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {5FE530AC-4A73-424F-A09C-BA80D3FAA134}
- EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27428.2011
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestTask", "TestTask.csproj", "{6E9922F2-AF75-4807-B6E4-F74499317C39}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6E9922F2-AF75-4807-B6E4-F74499317C39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6E9922F2-AF75-4807-B6E4-F74499317C39}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6E9922F2-AF75-4807-B6E4-F74499317C39}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6E9922F2-AF75-4807-B6E4-F74499317C39}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {5FE530AC-4A73-424F-A09C-BA80D3FAA134}
+ EndGlobalSection
+EndGlobal
diff --git a/data/file1.txt b/data/file1.txt
new file mode 100644
index 0000000..365a96e
--- /dev/null
+++ b/data/file1.txt
@@ -0,0 +1 @@
+Йода говорит мудро, но порядок слов меняет всегда.
diff --git a/data/file2.txt b/data/file2.txt
new file mode 100644
index 0000000..c540475
--- /dev/null
+++ b/data/file2.txt
@@ -0,0 +1 @@
+Фремены поодиночке уходили в пустыню Арракиса.