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 @@ +Фремены поодиночке уходили в пустыню Арракиса.