From d0feb675d07d559ae944af9850c3b05cd398f992 Mon Sep 17 00:00:00 2001 From: sibogatovr Date: Mon, 22 Jan 2024 00:05:00 +0500 Subject: [PATCH 01/13] init, hardcode, v1 --- TagsCloudContainer/CommandLineClient.cs | 26 +++++ TagsCloudContainer/GuiClient.cs | 26 +++++ .../Interfaces/ICircularCloudLayouter.cs | 11 ++ TagsCloudContainer/Interfaces/IFileReader.cs | 8 ++ .../Interfaces/IImageSettings.cs | 13 +++ .../Interfaces/INextPointProvider.cs | 9 ++ .../Interfaces/IPreprocessor.cs | 8 ++ .../Interfaces/ITagCloudClient.cs | 8 ++ .../Interfaces/ITagCloudGenerator.cs | 9 ++ TagsCloudContainer/Program.cs | 17 ++++ TagsCloudContainer/Readers/DocReader.cs | 34 +++++++ TagsCloudContainer/Readers/DocxReader.cs | 30 ++++++ TagsCloudContainer/Readers/TxtReader.cs | 27 +++++ TagsCloudContainer/Startup.cs | 22 ++++ .../TagsCloud/CircularCloudLayouter.cs | 82 +++++++++++++++ TagsCloudContainer/TagsCloud/ImageSettings.cs | 19 ++++ TagsCloudContainer/TagsCloud/TagCloudApp.cs | 94 ++++++++++++++++++ .../TagsCloud/TagCloudGenerator.cs | 29 ++++++ .../TagsCloud/WordPreprocessor.cs | 28 ++++++ TagsCloudContainer/TagsCloudContainer.csproj | 39 ++++++++ TagsCloudContainer/Utility/Spiral.cs | 54 ++++++++++ TagsCloudContainer/Utility/Visualizer.cs | 65 ++++++++++++ TagsCloudContainer/output/tagsCloud.png | Bin 0 -> 23890 bytes TagsCloudContainer/src/Oswald.ttf | Bin 0 -> 169108 bytes TagsCloudContainer/src/boring_words.txt | 3 + TagsCloudContainer/src/text.doc | Bin 0 -> 25600 bytes TagsCloudContainer/src/text.docx | Bin 0 -> 6169 bytes TagsCloudContainer/src/text.txt | 62 ++++++++++++ TagsCloudContainerTests/FileReaderTests.cs | 68 +++++++++++++ TagsCloudContainerTests/ProgramTests.cs | 31 ++++++ .../TagCloudGeneratorTests.cs | 32 ++++++ .../TagsCloudContainerTests.csproj | 26 +++++ TagsCloudContainerTests/WordPreprocessor.cs | 45 +++++++++ di.sln | 25 ++++- 34 files changed, 945 insertions(+), 5 deletions(-) create mode 100644 TagsCloudContainer/CommandLineClient.cs create mode 100644 TagsCloudContainer/GuiClient.cs create mode 100644 TagsCloudContainer/Interfaces/ICircularCloudLayouter.cs create mode 100644 TagsCloudContainer/Interfaces/IFileReader.cs create mode 100644 TagsCloudContainer/Interfaces/IImageSettings.cs create mode 100644 TagsCloudContainer/Interfaces/INextPointProvider.cs create mode 100644 TagsCloudContainer/Interfaces/IPreprocessor.cs create mode 100644 TagsCloudContainer/Interfaces/ITagCloudClient.cs create mode 100644 TagsCloudContainer/Interfaces/ITagCloudGenerator.cs create mode 100644 TagsCloudContainer/Program.cs create mode 100644 TagsCloudContainer/Readers/DocReader.cs create mode 100644 TagsCloudContainer/Readers/DocxReader.cs create mode 100644 TagsCloudContainer/Readers/TxtReader.cs create mode 100644 TagsCloudContainer/Startup.cs create mode 100644 TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs create mode 100644 TagsCloudContainer/TagsCloud/ImageSettings.cs create mode 100644 TagsCloudContainer/TagsCloud/TagCloudApp.cs create mode 100644 TagsCloudContainer/TagsCloud/TagCloudGenerator.cs create mode 100644 TagsCloudContainer/TagsCloud/WordPreprocessor.cs create mode 100644 TagsCloudContainer/TagsCloudContainer.csproj create mode 100644 TagsCloudContainer/Utility/Spiral.cs create mode 100644 TagsCloudContainer/Utility/Visualizer.cs create mode 100644 TagsCloudContainer/output/tagsCloud.png create mode 100644 TagsCloudContainer/src/Oswald.ttf create mode 100644 TagsCloudContainer/src/boring_words.txt create mode 100644 TagsCloudContainer/src/text.doc create mode 100644 TagsCloudContainer/src/text.docx create mode 100644 TagsCloudContainer/src/text.txt create mode 100644 TagsCloudContainerTests/FileReaderTests.cs create mode 100644 TagsCloudContainerTests/ProgramTests.cs create mode 100644 TagsCloudContainerTests/TagCloudGeneratorTests.cs create mode 100644 TagsCloudContainerTests/TagsCloudContainerTests.csproj create mode 100644 TagsCloudContainerTests/WordPreprocessor.cs diff --git a/TagsCloudContainer/CommandLineClient.cs b/TagsCloudContainer/CommandLineClient.cs new file mode 100644 index 000000000..cafb59b54 --- /dev/null +++ b/TagsCloudContainer/CommandLineClient.cs @@ -0,0 +1,26 @@ +using TagsCloudContainer.Interfaces; + +namespace TagsCloudContainer +{ + public class CommandLineClient : ITagCloudClient + { + private readonly IFileReader _fileReader; + private readonly IPreprocessor _preprocessor; + private readonly ITagCloudGenerator _tagCloudGenerator; + private readonly IImageSettings _imageSettings; + + public CommandLineClient(IFileReader fileReader, IPreprocessor preprocessor, + ITagCloudGenerator tagCloudGenerator, IImageSettings imageSettings) + { + _fileReader = fileReader; + _preprocessor = preprocessor; + _tagCloudGenerator = tagCloudGenerator; + _imageSettings = imageSettings; + } + + public void Run() + { + //TODO: Логика для CLI + } + } +} diff --git a/TagsCloudContainer/GuiClient.cs b/TagsCloudContainer/GuiClient.cs new file mode 100644 index 000000000..2bd246c67 --- /dev/null +++ b/TagsCloudContainer/GuiClient.cs @@ -0,0 +1,26 @@ +using TagsCloudContainer.Interfaces; + +namespace TagsCloudContainer +{ + public class GuiClient : ITagCloudClient + { + private readonly IFileReader _fileReader; + private readonly IPreprocessor _preprocessor; + private readonly ITagCloudGenerator _tagCloudGenerator; + private readonly IImageSettings _imageSettings; + + public GuiClient(IFileReader fileReader, IPreprocessor preprocessor, + ITagCloudGenerator tagCloudGenerator, IImageSettings imageSettings) + { + _fileReader = fileReader; + _preprocessor = preprocessor; + _tagCloudGenerator = tagCloudGenerator; + _imageSettings = imageSettings; + } + + public void Run() + { + //TODO: Логика для GUI + } + } +} diff --git a/TagsCloudContainer/Interfaces/ICircularCloudLayouter.cs b/TagsCloudContainer/Interfaces/ICircularCloudLayouter.cs new file mode 100644 index 000000000..84fdd7268 --- /dev/null +++ b/TagsCloudContainer/Interfaces/ICircularCloudLayouter.cs @@ -0,0 +1,11 @@ +using System.Drawing; + +namespace TagsCloudContainer.Interfaces +{ + public interface ICircularCloudLayouter + { + public Point CloudCenter { get; } + public IList Rectangles { get; } + Rectangle PutNextRectangle(string word, Font font); + } +} diff --git a/TagsCloudContainer/Interfaces/IFileReader.cs b/TagsCloudContainer/Interfaces/IFileReader.cs new file mode 100644 index 000000000..2ac078cfd --- /dev/null +++ b/TagsCloudContainer/Interfaces/IFileReader.cs @@ -0,0 +1,8 @@ + +namespace TagsCloudContainer.Interfaces +{ + public interface IFileReader + { + IEnumerable ReadWords(string filePath); + } +} diff --git a/TagsCloudContainer/Interfaces/IImageSettings.cs b/TagsCloudContainer/Interfaces/IImageSettings.cs new file mode 100644 index 000000000..83980c41a --- /dev/null +++ b/TagsCloudContainer/Interfaces/IImageSettings.cs @@ -0,0 +1,13 @@ +using System.Drawing; + +namespace TagsCloudContainer.Interfaces +{ + public interface IImageSettings + { + Color BackgroundColor { get; } + Color FontColor { get; } + Font GetFont(); + int ImageWidth { get; } + int ImageHeight { get; } + } +} diff --git a/TagsCloudContainer/Interfaces/INextPointProvider.cs b/TagsCloudContainer/Interfaces/INextPointProvider.cs new file mode 100644 index 000000000..c63947a32 --- /dev/null +++ b/TagsCloudContainer/Interfaces/INextPointProvider.cs @@ -0,0 +1,9 @@ +using System.Drawing; + +namespace TagsCloudContainer.Interfaces +{ + public interface INextPointProvider + { + Point GetNextPoint(); + } +} diff --git a/TagsCloudContainer/Interfaces/IPreprocessor.cs b/TagsCloudContainer/Interfaces/IPreprocessor.cs new file mode 100644 index 000000000..2c8998822 --- /dev/null +++ b/TagsCloudContainer/Interfaces/IPreprocessor.cs @@ -0,0 +1,8 @@ + +namespace TagsCloudContainer.Interfaces +{ + public interface IPreprocessor + { + IEnumerable Process(IEnumerable words); + } +} diff --git a/TagsCloudContainer/Interfaces/ITagCloudClient.cs b/TagsCloudContainer/Interfaces/ITagCloudClient.cs new file mode 100644 index 000000000..9d5f49638 --- /dev/null +++ b/TagsCloudContainer/Interfaces/ITagCloudClient.cs @@ -0,0 +1,8 @@ + +namespace TagsCloudContainer.Interfaces +{ + public interface ITagCloudClient + { + void Run(); + } +} diff --git a/TagsCloudContainer/Interfaces/ITagCloudGenerator.cs b/TagsCloudContainer/Interfaces/ITagCloudGenerator.cs new file mode 100644 index 000000000..0be0c2cf2 --- /dev/null +++ b/TagsCloudContainer/Interfaces/ITagCloudGenerator.cs @@ -0,0 +1,9 @@ +using System.Drawing; + +namespace TagsCloudContainer.Interfaces +{ + public interface ITagCloudGenerator + { + Bitmap GenerateTagCloud(IEnumerable words, IImageSettings imageSettings); + } +} diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs new file mode 100644 index 000000000..87d22567c --- /dev/null +++ b/TagsCloudContainer/Program.cs @@ -0,0 +1,17 @@ +using Microsoft.Extensions.DependencyInjection; +using TagsCloudContainer.TagsCloud; + +namespace TagsCloudContainer +{ + public class Program + { + static void Main(string[] args) + { + using (var serviceProvider = Startup.ConfigureServices()) + { + var tagCloudApp = serviceProvider.GetRequiredService(); + tagCloudApp.Run("src/text.txt"); + } + } + } +} diff --git a/TagsCloudContainer/Readers/DocReader.cs b/TagsCloudContainer/Readers/DocReader.cs new file mode 100644 index 000000000..95309f3a4 --- /dev/null +++ b/TagsCloudContainer/Readers/DocReader.cs @@ -0,0 +1,34 @@ +using Spire.Doc; +using Spire.Doc.Documents; +using TagsCloudContainer.Interfaces; + +namespace TagsCloudContainer.Readers +{ + public class DocReader : IFileReader + { + public IEnumerable ReadWords(string filePath) + { + var words = new List(); + + try + { + var document = new Document(); + document.LoadFromFile(filePath); + + foreach (Section section in document.Sections) + { + foreach (Paragraph paragraph in section.Paragraphs) + { + words.AddRange(paragraph.Text.Split(' ', StringSplitOptions.RemoveEmptyEntries)); + } + } + } + catch (Exception ex) + { + Console.WriteLine($"Error reading .doc file: {ex.Message}"); + } + + return words; + } + } +} diff --git a/TagsCloudContainer/Readers/DocxReader.cs b/TagsCloudContainer/Readers/DocxReader.cs new file mode 100644 index 000000000..0cf9ad4c8 --- /dev/null +++ b/TagsCloudContainer/Readers/DocxReader.cs @@ -0,0 +1,30 @@ +using NPOI.XWPF.UserModel; +using TagsCloudContainer.Interfaces; + +namespace TagsCloudContainer.Readers +{ + public class DocxReader : IFileReader + { + public IEnumerable ReadWords(string filePath) + { + var words = new List(); + + try + { + using (var doc = new XWPFDocument(File.OpenRead(filePath))) + { + foreach (var paragraph in doc.Paragraphs) + { + words.AddRange(paragraph.Text.Split(' ', StringSplitOptions.RemoveEmptyEntries)); + } + } + } + catch (Exception ex) + { + Console.WriteLine($"Error reading .docx file: {ex.Message}"); + } + + return words; + } + } +} diff --git a/TagsCloudContainer/Readers/TxtReader.cs b/TagsCloudContainer/Readers/TxtReader.cs new file mode 100644 index 000000000..d12633639 --- /dev/null +++ b/TagsCloudContainer/Readers/TxtReader.cs @@ -0,0 +1,27 @@ +using TagsCloudContainer.Interfaces; + +namespace TagsCloudContainer.Readers +{ + public class TxtReader : IFileReader + { + public IEnumerable ReadWords(string filePath) + { + try + { + string[] lines = File.ReadAllLines(filePath); + + var words = lines.SelectMany(line => line.Split(' ')); + + var nonEmptyWords = words.Where(word => !string.IsNullOrEmpty(word)); + + return nonEmptyWords; + } + catch (Exception ex) + { + + Console.WriteLine($"Error reading file: {ex.Message}"); + return Enumerable.Empty(); + } + } + } +} diff --git a/TagsCloudContainer/Startup.cs b/TagsCloudContainer/Startup.cs new file mode 100644 index 000000000..77fea5d35 --- /dev/null +++ b/TagsCloudContainer/Startup.cs @@ -0,0 +1,22 @@ +using Microsoft.Extensions.DependencyInjection; +using TagsCloudContainer.Interfaces; +using TagsCloudContainer.Readers; +using TagsCloudContainer.TagsCloud; + +namespace TagsCloudContainer +{ + public class Startup + { + public static ServiceProvider ConfigureServices() + { + return new ServiceCollection() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .BuildServiceProvider(); + } + } +} diff --git a/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs b/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs new file mode 100644 index 000000000..e75263f22 --- /dev/null +++ b/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs @@ -0,0 +1,82 @@ +using System.Drawing; +using TagsCloudContainer.Interfaces; + +namespace TagsCloudContainer.TagsCloud +{ + public class CircularCloudLayouter : ICircularCloudLayouter + { + private readonly Point center; + private readonly List rectangles; + private readonly INextPointProvider pointProvider; + + public CircularCloudLayouter(Point center, INextPointProvider pointProvider) + { + this.center = center; + rectangles = new(); + this.pointProvider = pointProvider; + } + + public Point CloudCenter => center; + public IList Rectangles => rectangles; + + public Rectangle PutNextRectangle(Size rectangleSize) + { + ValidateRectangleSize(rectangleSize); + + var currentRectangle = CreateNewRectangle(rectangleSize); + rectangles.Add(currentRectangle); + + return currentRectangle; + } + + public Rectangle PutNextRectangle(string word, Font font) + { + var textSize = MeasureTextSize(word, font); + return PutNextRectangle(textSize); + } + + private Size MeasureTextSize(string text, Font font) + { + using (var temporaryBitmap = new Bitmap(1, 1)) + using (var temporaryGraphics = Graphics.FromImage(temporaryBitmap)) + { + return Size.Ceiling(temporaryGraphics.MeasureString(text, font)); + } + } + + private void ValidateRectangleSize(Size rectangleSize) + { + if (rectangleSize.Width <= 0 || rectangleSize.Height <= 0) + { + throw new ArgumentException("Width and height of the rectangle must be greater than zero"); + } + } + + private Rectangle CreateNewRectangle(Size rectangleSize) + { + while (true) + { + var nextPoint = pointProvider.GetNextPoint(); + var rectangleLocation = GetUpperLeftCorner(nextPoint, rectangleSize); + var rectangle = new Rectangle(rectangleLocation, rectangleSize); + + if (!RectanglesIntersect(rectangle)) + { + return rectangle; + } + } + } + + private Point GetUpperLeftCorner(Point rectangleCenter, Size rectangleSize) + { + return new Point(rectangleCenter.X - rectangleSize.Width / 2, rectangleCenter.Y - rectangleSize.Height / 2); + } + + private bool RectanglesIntersect(Rectangle newRectangle) + { + return rectangles.Any(rect => rect.IntersectsWith(newRectangle)); + } + + + } +} diff --git a/TagsCloudContainer/TagsCloud/ImageSettings.cs b/TagsCloudContainer/TagsCloud/ImageSettings.cs new file mode 100644 index 000000000..c42d3a1f8 --- /dev/null +++ b/TagsCloudContainer/TagsCloud/ImageSettings.cs @@ -0,0 +1,19 @@ +using System.Drawing; +using TagsCloudContainer.Interfaces; + +namespace TagsCloudContainer.TagsCloud +{ + public class ImageSettings : IImageSettings + { + public Color BackgroundColor { get; } = Color.White; + public Color FontColor { get; } = Color.Black; + public int ImageWidth { get; } = 1600; + public int ImageHeight { get; } = 1200; + + public Font GetFont() + { + return new Font("Verdana", 20); + } + + } +} diff --git a/TagsCloudContainer/TagsCloud/TagCloudApp.cs b/TagsCloudContainer/TagsCloud/TagCloudApp.cs new file mode 100644 index 000000000..808e20f58 --- /dev/null +++ b/TagsCloudContainer/TagsCloud/TagCloudApp.cs @@ -0,0 +1,94 @@ +using System.Drawing.Imaging; +using System.Drawing; +using TagsCloudContainer.Interfaces; +using TagsCloudContainer.Utility; + +namespace TagsCloudContainer.TagsCloud +{ + public class TagCloudApp + { + private readonly IFileReader _fileReader; + private readonly IPreprocessor _preprocessor; + private readonly ITagCloudGenerator _tagCloudGenerator; + private readonly IImageSettings _imageSettings; + + public TagCloudApp(IFileReader fileReader, IPreprocessor preprocessor, ITagCloudGenerator tagCloudGenerator, IImageSettings imageSettings) + { + _fileReader = fileReader; + _preprocessor = preprocessor; + _tagCloudGenerator = tagCloudGenerator; + _imageSettings = imageSettings; + } + + public void Run(string filePath) + { + var words = _fileReader.ReadWords(filePath); + var processedWords = _preprocessor.Process(words); + + Console.WriteLine("Processed words:\n"); + + foreach (var item in processedWords) + { + Console.WriteLine(item); + } + + var tagCloudImage = GenerateTagCloud(processedWords); + + tagCloudImage.Save(@"..\..\..\output\tagsCloud.png", ImageFormat.Png); + + Console.WriteLine("Tag cloud image saved to: /output/"); + } + + private Bitmap GenerateTagCloud(IEnumerable words) + { + var layouter = CreateLayouter(); + var uniqueWords = new HashSet(); + var wordFrequencies = CalculateWordFrequencies(words); + + var mostPopularWord = wordFrequencies.OrderByDescending(pair => pair.Value).FirstOrDefault().Key; + + var sortedWords = words.OrderByDescending(word => wordFrequencies[word]); + + foreach (var word in sortedWords) + { + if (uniqueWords.Add(word)) // Проверяем и добавляем в хеш-сет, возвращая true, если слово уникально + { + var font = new Font("Arial", CalculateFontSize(word, wordFrequencies, mostPopularWord)); + layouter.PutNextRectangle(word, font); + } + } + + var rectangles = layouter.Rectangles.ToList(); + return Visualizer.VisualizeRectangles(rectangles, uniqueWords, _imageSettings.ImageWidth, _imageSettings.ImageHeight); + } + + private Dictionary CalculateWordFrequencies(IEnumerable words) + { + var wordFrequencies = new Dictionary(); + + foreach (var word in words) + { + wordFrequencies.TryGetValue(word, out var frequency); + wordFrequencies[word] = frequency + 1; + } + + return wordFrequencies; + } + + private CircularCloudLayouter CreateLayouter() + { + var center = new Point(_imageSettings.ImageWidth / 2, _imageSettings.ImageHeight / 2); + var spiral = new Spiral(center, 0.02, 0.04); + return new CircularCloudLayouter(center, spiral); + } + + private int CalculateFontSize(string word, Dictionary wordFrequencies, string mostPopularWord) + { + if (wordFrequencies.TryGetValue(word, out var frequency)) + { + return Math.Max(35, 35 + frequency * 2); + } + return 10; + } + } +} diff --git a/TagsCloudContainer/TagsCloud/TagCloudGenerator.cs b/TagsCloudContainer/TagsCloud/TagCloudGenerator.cs new file mode 100644 index 000000000..68946c7cc --- /dev/null +++ b/TagsCloudContainer/TagsCloud/TagCloudGenerator.cs @@ -0,0 +1,29 @@ +using System.Drawing; +using TagsCloudContainer.Interfaces; + +namespace TagsCloudContainer.TagsCloud +{ + public class TagCloudGenerator : ITagCloudGenerator + { + public Bitmap GenerateTagCloud(IEnumerable words, IImageSettings imageSettings) + { + var tagCloudImage = new Bitmap(imageSettings.ImageWidth, imageSettings.ImageHeight); + using (var graphics = Graphics.FromImage(tagCloudImage)) + { + graphics.Clear(imageSettings.BackgroundColor); + var font = imageSettings.GetFont(); + var brush = new SolidBrush(imageSettings.FontColor); + + int yOffset = 0; + foreach (var word in words) + { + graphics.DrawString(word, font, brush, new PointF(0, yOffset)); + yOffset += font.Height; + } + } + + return tagCloudImage; + } + } +} + diff --git a/TagsCloudContainer/TagsCloud/WordPreprocessor.cs b/TagsCloudContainer/TagsCloud/WordPreprocessor.cs new file mode 100644 index 000000000..f52454bd3 --- /dev/null +++ b/TagsCloudContainer/TagsCloud/WordPreprocessor.cs @@ -0,0 +1,28 @@ +using TagsCloudContainer.Interfaces; + +namespace TagsCloudContainer.TagsCloud +{ + public class WordPreprocessor : IPreprocessor + { + private readonly HashSet boringWords; + + public WordPreprocessor(IEnumerable boringWords) + { + this.boringWords = new HashSet(boringWords, StringComparer.OrdinalIgnoreCase); + } + + public IEnumerable Process(IEnumerable words) + { + var lowercasedWords = words.Select(word => word.ToLower()); + + var filteredWords = lowercasedWords.Where(word => !IsBoringWord(word)); + + return filteredWords; + } + + private bool IsBoringWord(string word) + { + return boringWords.Contains(word); + } + } +} diff --git a/TagsCloudContainer/TagsCloudContainer.csproj b/TagsCloudContainer/TagsCloudContainer.csproj new file mode 100644 index 000000000..75dc4a469 --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer.csproj @@ -0,0 +1,39 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + + + + + Always + + + Always + + + Always + + + Always + + + Always + + + + diff --git a/TagsCloudContainer/Utility/Spiral.cs b/TagsCloudContainer/Utility/Spiral.cs new file mode 100644 index 000000000..a8a7b7789 --- /dev/null +++ b/TagsCloudContainer/Utility/Spiral.cs @@ -0,0 +1,54 @@ +using System.Drawing; +using TagsCloudContainer.Interfaces; + +namespace TagsCloudContainer.Utility +{ + public class Spiral : INextPointProvider + { + private readonly Point center; + private readonly double angleStep; + private readonly double radiusStep; + private double angle; + private double radius; + + + public Point GetNextPoint() + { + var point = ConvertFromPolarToCartesian(angle, radius); + point.Offset(center); + angle += angleStep; + radius += radiusStep; + return point; + } + + public Spiral(Point center, double angleStep, double radiusStep) + { + if (radiusStep <= 0 || angleStep <= 0) + { + throw new ArgumentException("Step values should be positive."); + } + + this.center = center; + this.angleStep = angleStep; + this.radiusStep = radiusStep; + } + + + public IEnumerable GetPointsOnSpiral() + { + for (double angle = 0, radius = 0; ; angle += angleStep, radius += radiusStep) + { + var point = ConvertFromPolarToCartesian(angle, radius); + point.Offset(center); + yield return point; + } + } + + private static Point ConvertFromPolarToCartesian(double angle, double radius) + { + var x = (int)Math.Round(Math.Cos(angle) * radius); + var y = (int)Math.Round(Math.Sin(angle) * radius); + return new Point(x, y); + } + } +} diff --git a/TagsCloudContainer/Utility/Visualizer.cs b/TagsCloudContainer/Utility/Visualizer.cs new file mode 100644 index 000000000..4924dc074 --- /dev/null +++ b/TagsCloudContainer/Utility/Visualizer.cs @@ -0,0 +1,65 @@ +using System.Drawing; + +namespace TagsCloudContainer.Utility +{ + public static class Visualizer + { + public static Bitmap VisualizeRectangles(List rectangles, HashSet uniqueWords, int bitmapWidth, int bitmapHeight) + { + var bitmap = new Bitmap(bitmapWidth, bitmapHeight); + using var graphics = Graphics.FromImage(bitmap); + + for (var i = 0; i < rectangles.Count; i++) + { + var rect = rectangles[i]; + var word = uniqueWords.ElementAt(i); + + var fontSize = rect.Width / word.Length; + var font = new Font("Arial", fontSize, FontStyle.Regular); + + var brushColor = word == GetMostPopularWord(uniqueWords) ? Color.Green : Color.Black; + var brush = new SolidBrush(brushColor); + + graphics.DrawString(word, font, brush, rect); + } + + return bitmap; + } + + private static string GetMostPopularWord(HashSet uniqueWords) + { + return uniqueWords.FirstOrDefault(); + } + + //private static void DrawRectangles(IEnumerable rectangles, Graphics graphics) + //{ + // var pen = new Pen(Color.Green); + // foreach (var rect in rectangles) + // { + // graphics.DrawRectangle(pen, rect); + // } + //} + + public static void SaveBitmap(Bitmap bitmap, string fileName, string pathToDirectory) + { + EnsureDirectoryExists(pathToDirectory); + + var safeFileName = GetSafeFileName(fileName); + bitmap.Save(Path.Combine(pathToDirectory, safeFileName), System.Drawing.Imaging.ImageFormat.Png); + } + + private static void EnsureDirectoryExists(string directory) + { + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + } + + private static string GetSafeFileName(string fileName) + { + var invalidChars = Path.GetInvalidFileNameChars(); + return string.Concat(fileName.Split(invalidChars, StringSplitOptions.RemoveEmptyEntries)); + } + } +} diff --git a/TagsCloudContainer/output/tagsCloud.png b/TagsCloudContainer/output/tagsCloud.png new file mode 100644 index 0000000000000000000000000000000000000000..c5ee0316e4cf4737429c2c781af5f0f112a7b8ec GIT binary patch literal 23890 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 literal 0 HcmV?d00001 diff --git a/TagsCloudContainer/src/boring_words.txt b/TagsCloudContainer/src/boring_words.txt new file mode 100644 index 000000000..089f68000 --- /dev/null +++ b/TagsCloudContainer/src/boring_words.txt @@ -0,0 +1,3 @@ +a +an +the \ No newline at end of file diff --git a/TagsCloudContainer/src/text.doc b/TagsCloudContainer/src/text.doc new file mode 100644 index 0000000000000000000000000000000000000000..f9deb0d3a5f9c5a623395aebe9e9f7e7763d9db3 GIT binary patch literal 25600 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 IIW`*jFHI_^)&Kwi literal 0 HcmV?d00001 diff --git a/TagsCloudContainer/src/text.docx b/TagsCloudContainer/src/text.docx new file mode 100644 index 0000000000000000000000000000000000000000..f7170c799e2fdb76929ae39a030a939427377bc3 GIT binary patch literal 6169 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 fileReaderMock; + private Mock preprocessorMock; + private Mock tagCloudGeneratorMock; + private Mock imageSettingsMock; + + private Program program; + + [SetUp] + public void SetUp() + { + //fileReaderMock = new Mock(); + //preprocessorMock = new Mock(); + //tagCloudGeneratorMock = new Mock(); + //imageSettingsMock = new Mock(); + + //program = new Program(fileReaderMock.Object, preprocessorMock.Object, tagCloudGeneratorMock.Object, imageSettingsMock.Object); + } + + + } +} diff --git a/TagsCloudContainerTests/TagCloudGeneratorTests.cs b/TagsCloudContainerTests/TagCloudGeneratorTests.cs new file mode 100644 index 000000000..e654b3ce9 --- /dev/null +++ b/TagsCloudContainerTests/TagCloudGeneratorTests.cs @@ -0,0 +1,32 @@ +using TagsCloudContainer.Interfaces; +using TagsCloudContainer; +using NUnit.Framework; +using FluentAssertions; +using TagsCloudContainer.TagsCloud; + +namespace TagsCloudContainerTests +{ + [TestFixture] + public class TagCloudGeneratorTests + { + private ITagCloudGenerator tagCloudGenerator; + + [SetUp] + public void SetUp() + { + tagCloudGenerator = new TagCloudGenerator(); + } + + [Test] + public void GenerateTagCloud_ValidData_ReturnsImage() + { + var words = new[] { "apple", "banana", "orange", "apple", "banana" }; + + var imageSettings = new ImageSettings(); + + var tagCloudImage = tagCloudGenerator.GenerateTagCloud(words, imageSettings); + + tagCloudImage.Should().NotBeNull(); + } + } +} diff --git a/TagsCloudContainerTests/TagsCloudContainerTests.csproj b/TagsCloudContainerTests/TagsCloudContainerTests.csproj new file mode 100644 index 000000000..eac6f7244 --- /dev/null +++ b/TagsCloudContainerTests/TagsCloudContainerTests.csproj @@ -0,0 +1,26 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + diff --git a/TagsCloudContainerTests/WordPreprocessor.cs b/TagsCloudContainerTests/WordPreprocessor.cs new file mode 100644 index 000000000..1c3bf5f1c --- /dev/null +++ b/TagsCloudContainerTests/WordPreprocessor.cs @@ -0,0 +1,45 @@ +using TagsCloudContainer.Interfaces; +using NUnit.Framework; +using FluentAssertions; +using TagsCloudContainer.TagsCloud; + +namespace TagsCloudContainerTests +{ + [TestFixture] + public class WordPreprocessorTests + { + private IPreprocessor preprocessor; + [SetUp] + public void SetUp() + { + preprocessor = new WordPreprocessor(new List()); + } + + [Test] + public void WithCommonWords_RemovesCommonWords() + { + var boringWords = new List { "the", "a" }; + preprocessor = new WordPreprocessor(boringWords); + + var words = new[] { "the", "quick", "a", "fox", "jumps" }; + + var processedWords = preprocessor.Process(words); + + processedWords.Should().HaveCount(3); + processedWords.Should().NotContain("a"); + processedWords.Should().NotContain("the"); + } + + [Test] + public void WithUpperCase_ConvertsToLowercase() + { + var words = new[] { "Word1", "Word2", "Word3" }; + + var processedWords = preprocessor.Process(words); + + processedWords.Should().BeEquivalentTo("word1", "word2", "word3"); + } + } + +} + diff --git a/di.sln b/di.sln index b27b7c05d..7e5ed6c8e 100644 --- a/di.sln +++ b/di.sln @@ -1,6 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FractalPainter", "FractalPainter\FractalPainter.csproj", "{4D70883B-6F8B-4166-802F-8EDC9BE93199}" +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34330.188 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagsCloudContainer", "TagsCloudContainer\TagsCloudContainer.csproj", "{B6AFBD5A-A82F-4668-9C7F-881512BB9EDF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagsCloudContainerTests", "TagsCloudContainerTests\TagsCloudContainerTests.csproj", "{05D64DA4-A1B9-401F-AD25-6D4AEBEE68B5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -8,9 +13,19 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4D70883B-6F8B-4166-802F-8EDC9BE93199}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4D70883B-6F8B-4166-802F-8EDC9BE93199}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4D70883B-6F8B-4166-802F-8EDC9BE93199}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4D70883B-6F8B-4166-802F-8EDC9BE93199}.Release|Any CPU.Build.0 = Release|Any CPU + {B6AFBD5A-A82F-4668-9C7F-881512BB9EDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6AFBD5A-A82F-4668-9C7F-881512BB9EDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6AFBD5A-A82F-4668-9C7F-881512BB9EDF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6AFBD5A-A82F-4668-9C7F-881512BB9EDF}.Release|Any CPU.Build.0 = Release|Any CPU + {05D64DA4-A1B9-401F-AD25-6D4AEBEE68B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {05D64DA4-A1B9-401F-AD25-6D4AEBEE68B5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {05D64DA4-A1B9-401F-AD25-6D4AEBEE68B5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {05D64DA4-A1B9-401F-AD25-6D4AEBEE68B5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4994D982-F2FE-4BC8-820A-6E567F12810C} EndGlobalSection EndGlobal From 5cffcd99892b4add5965b74dfc95914ddb402da9 Mon Sep 17 00:00:00 2001 From: sibogatovr Date: Mon, 22 Jan 2024 16:41:21 +0500 Subject: [PATCH 02/13] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B9?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=A8=D1=80=D0=B8=D1=84=D1=82=D0=B0,=20=D0=A1?= =?UTF-8?q?=D0=BA=D1=83=D1=87=D0=BD=D1=8B=D1=85=20=D1=81=D0=BB=D0=BE=D0=B2?= =?UTF-8?q?,=20=20=D0=A6=D0=B2=D0=B5=D1=82=D0=B0,=20=D0=A6=D0=B2=D0=B5?= =?UTF-8?q?=D1=82=D0=B0=20=D0=BF=D0=BE=D0=BF=D1=83=D0=BB=D1=8F=D1=80=D0=BD?= =?UTF-8?q?=D1=8B=D1=85=20=D1=81=D0=BB=D0=BE=D0=B2,=20=D0=B0=D0=BB=D0=B3?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D1=82=D0=BC=20=D0=BF=D0=BE=D0=BA=D1=80=D0=B0?= =?UTF-8?q?=D1=81=D0=BA=D0=B8=20=D1=81=D0=BB=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Interfaces/IPreprocessor.cs | 2 +- TagsCloudContainer/Program.cs | 11 ++- TagsCloudContainer/Startup.cs | 25 +++++-- TagsCloudContainer/TagsCloud/TagCloudApp.cs | 69 +++++++++++++----- .../TagsCloud/WordPreprocessor.cs | 9 ++- TagsCloudContainer/TagsCloudContainer.csproj | 2 +- TagsCloudContainer/Utility/Visualizer.cs | 18 +++-- TagsCloudContainer/output/tagsCloud.png | Bin 23890 -> 27950 bytes di.sln | 4 +- 9 files changed, 98 insertions(+), 42 deletions(-) diff --git a/TagsCloudContainer/Interfaces/IPreprocessor.cs b/TagsCloudContainer/Interfaces/IPreprocessor.cs index 2c8998822..1840fe030 100644 --- a/TagsCloudContainer/Interfaces/IPreprocessor.cs +++ b/TagsCloudContainer/Interfaces/IPreprocessor.cs @@ -3,6 +3,6 @@ namespace TagsCloudContainer.Interfaces { public interface IPreprocessor { - IEnumerable Process(IEnumerable words); + IEnumerable Process(IEnumerable words, string boringWordsFilePath); } } diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs index 87d22567c..247d5dfe6 100644 --- a/TagsCloudContainer/Program.cs +++ b/TagsCloudContainer/Program.cs @@ -1,16 +1,23 @@ using Microsoft.Extensions.DependencyInjection; +using System.Drawing; using TagsCloudContainer.TagsCloud; namespace TagsCloudContainer { public class Program { - static void Main(string[] args) + static void Main(string[] args) { using (var serviceProvider = Startup.ConfigureServices()) { var tagCloudApp = serviceProvider.GetRequiredService(); - tagCloudApp.Run("src/text.txt"); + + tagCloudApp.Run("src/text.doc", // Исходный файл со словами + "src/boring_words.txt", // Файл со скучными словами + "Georgia", // Шрифт текста + Color.Black, // Цвет основного текста + Color.Red, // Цвет популярных слов + 0.2); // % Окрашивания популярных слов (топ-20%) } } } diff --git a/TagsCloudContainer/Startup.cs b/TagsCloudContainer/Startup.cs index 77fea5d35..bbaa516b9 100644 --- a/TagsCloudContainer/Startup.cs +++ b/TagsCloudContainer/Startup.cs @@ -10,13 +10,22 @@ public class Startup public static ServiceProvider ConfigureServices() { return new ServiceCollection() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .BuildServiceProvider(); - } + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddScoped(provider => + { + var fileReader = provider.GetRequiredService(); + var preprocessor = provider.GetRequiredService(); + var tagCloudGenerator = provider.GetRequiredService(); + var imageSettings = provider.GetRequiredService(); + + + return new TagCloudApp(preprocessor, imageSettings); + }) + .BuildServiceProvider(); + } } } diff --git a/TagsCloudContainer/TagsCloud/TagCloudApp.cs b/TagsCloudContainer/TagsCloud/TagCloudApp.cs index 808e20f58..4b0205780 100644 --- a/TagsCloudContainer/TagsCloud/TagCloudApp.cs +++ b/TagsCloudContainer/TagsCloud/TagCloudApp.cs @@ -1,29 +1,33 @@ -using System.Drawing.Imaging; -using System.Drawing; +using System.Drawing; using TagsCloudContainer.Interfaces; using TagsCloudContainer.Utility; +using TagsCloudContainer.Readers; namespace TagsCloudContainer.TagsCloud { public class TagCloudApp { - private readonly IFileReader _fileReader; private readonly IPreprocessor _preprocessor; - private readonly ITagCloudGenerator _tagCloudGenerator; private readonly IImageSettings _imageSettings; + private string _fontName; - public TagCloudApp(IFileReader fileReader, IPreprocessor preprocessor, ITagCloudGenerator tagCloudGenerator, IImageSettings imageSettings) + public TagCloudApp(IPreprocessor preprocessor, IImageSettings imageSettings) { - _fileReader = fileReader; _preprocessor = preprocessor; - _tagCloudGenerator = tagCloudGenerator; _imageSettings = imageSettings; } - public void Run(string filePath) + public void SetFontName(string fontName) { - var words = _fileReader.ReadWords(filePath); - var processedWords = _preprocessor.Process(words); + _fontName = fontName; + } + + public void Run(string filePath, string boringWordsFilePath, string fontName, Color fontColor, Color highlightColor, double percentageToHighlight) + { + SetFontName(fontName); + + var words = ReadFile(filePath); + var processedWords = _preprocessor.Process(words, boringWordsFilePath); Console.WriteLine("Processed words:\n"); @@ -32,14 +36,36 @@ public void Run(string filePath) Console.WriteLine(item); } - var tagCloudImage = GenerateTagCloud(processedWords); - - tagCloudImage.Save(@"..\..\..\output\tagsCloud.png", ImageFormat.Png); + var tagCloudImage = GenerateTagCloud(processedWords, fontName, fontColor, highlightColor, percentageToHighlight); + tagCloudImage.Save(@"..\..\..\output\tagsCloud.png"); Console.WriteLine("Tag cloud image saved to: /output/"); } - private Bitmap GenerateTagCloud(IEnumerable words) + private IEnumerable ReadFile(string filePath) + { + var fileReader = GetFileReader(filePath); + return fileReader.ReadWords(filePath); + } + + private IFileReader GetFileReader(string filePath) + { + string fileExtension = Path.GetExtension(filePath)?.ToLower(); + + switch (fileExtension) + { + case ".doc": + return new DocReader(); + case ".docx": + return new DocxReader(); + case ".txt": + return new TxtReader(); + default: + throw new InvalidOperationException("Unsupported file extension"); + } + } + + private Bitmap GenerateTagCloud(IEnumerable words, string fontName, Color fontColor, Color highlightColor, double percentageToHighlight) { var layouter = CreateLayouter(); var uniqueWords = new HashSet(); @@ -49,17 +75,24 @@ private Bitmap GenerateTagCloud(IEnumerable words) var sortedWords = words.OrderByDescending(word => wordFrequencies[word]); + var fontSizes = new List(); + foreach (var word in sortedWords) { - if (uniqueWords.Add(word)) // Проверяем и добавляем в хеш-сет, возвращая true, если слово уникально + if (uniqueWords.Add(word)) { - var font = new Font("Arial", CalculateFontSize(word, wordFrequencies, mostPopularWord)); + var fontSize = CalculateFontSize(word, wordFrequencies, mostPopularWord); + fontSizes.Add(fontSize); + + var font = new Font(fontName, fontSize); layouter.PutNextRectangle(word, font); } } var rectangles = layouter.Rectangles.ToList(); - return Visualizer.VisualizeRectangles(rectangles, uniqueWords, _imageSettings.ImageWidth, _imageSettings.ImageHeight); + + return Visualizer.VisualizeRectangles(rectangles, uniqueWords, _imageSettings.ImageWidth, _imageSettings.ImageHeight, + fontSizes, _fontName, fontColor, highlightColor, percentageToHighlight, wordFrequencies: wordFrequencies); } private Dictionary CalculateWordFrequencies(IEnumerable words) @@ -86,7 +119,7 @@ private int CalculateFontSize(string word, Dictionary wordFrequenci { if (wordFrequencies.TryGetValue(word, out var frequency)) { - return Math.Max(35, 35 + frequency * 2); + return Math.Max(30, 30 + frequency * 2); } return 10; } diff --git a/TagsCloudContainer/TagsCloud/WordPreprocessor.cs b/TagsCloudContainer/TagsCloud/WordPreprocessor.cs index f52454bd3..bb985eda8 100644 --- a/TagsCloudContainer/TagsCloud/WordPreprocessor.cs +++ b/TagsCloudContainer/TagsCloud/WordPreprocessor.cs @@ -11,18 +11,21 @@ public WordPreprocessor(IEnumerable boringWords) this.boringWords = new HashSet(boringWords, StringComparer.OrdinalIgnoreCase); } - public IEnumerable Process(IEnumerable words) + public IEnumerable Process(IEnumerable words, string boringWordsFilePath) { var lowercasedWords = words.Select(word => word.ToLower()); - var filteredWords = lowercasedWords.Where(word => !IsBoringWord(word)); + var boringWordsFromFile = File.ReadAllLines(boringWordsFilePath).Select(line => line.ToLower()).ToHashSet(); + + var filteredWords = lowercasedWords.Where(word => !IsBoringWord(word, boringWordsFromFile)); return filteredWords; } - private bool IsBoringWord(string word) + private bool IsBoringWord(string word, HashSet boringWords) { return boringWords.Contains(word); } + } } diff --git a/TagsCloudContainer/TagsCloudContainer.csproj b/TagsCloudContainer/TagsCloudContainer.csproj index 75dc4a469..15c0d36fa 100644 --- a/TagsCloudContainer/TagsCloudContainer.csproj +++ b/TagsCloudContainer/TagsCloudContainer.csproj @@ -10,8 +10,8 @@ + - diff --git a/TagsCloudContainer/Utility/Visualizer.cs b/TagsCloudContainer/Utility/Visualizer.cs index 4924dc074..6400afd68 100644 --- a/TagsCloudContainer/Utility/Visualizer.cs +++ b/TagsCloudContainer/Utility/Visualizer.cs @@ -4,20 +4,23 @@ namespace TagsCloudContainer.Utility { public static class Visualizer { - public static Bitmap VisualizeRectangles(List rectangles, HashSet uniqueWords, int bitmapWidth, int bitmapHeight) + public static Bitmap VisualizeRectangles(List rectangles, HashSet uniqueWords, + int bitmapWidth, int bitmapHeight, List fontSizes, string fontName, Color fontColor, Color highlightColor, double percentageToHighlight, + Dictionary wordFrequencies) { var bitmap = new Bitmap(bitmapWidth, bitmapHeight); using var graphics = Graphics.FromImage(bitmap); + var mostPopularWords = GetMostPopularWords(uniqueWords, percentageToHighlight, wordFrequencies); for (var i = 0; i < rectangles.Count; i++) { var rect = rectangles[i]; - var word = uniqueWords.ElementAt(i); + var word = uniqueWords.ElementAt(i).ToLower(); - var fontSize = rect.Width / word.Length; - var font = new Font("Arial", fontSize, FontStyle.Regular); + var fontSize = fontSizes[i]; + var font = new Font(fontName, fontSize, FontStyle.Regular); - var brushColor = word == GetMostPopularWord(uniqueWords) ? Color.Green : Color.Black; + var brushColor = mostPopularWords.Contains(word) ? highlightColor : fontColor; var brush = new SolidBrush(brushColor); graphics.DrawString(word, font, brush, rect); @@ -26,9 +29,10 @@ public static Bitmap VisualizeRectangles(List rectangles, HashSet uniqueWords) + private static List GetMostPopularWords(HashSet uniqueWords, double percentage, Dictionary wordFrequencies) { - return uniqueWords.FirstOrDefault(); + int countToHighlight = (int)Math.Ceiling(uniqueWords.Count * percentage); + return uniqueWords.OrderByDescending(word => wordFrequencies[word]).Take(countToHighlight).ToList(); } //private static void DrawRectangles(IEnumerable rectangles, Graphics graphics) diff --git a/TagsCloudContainer/output/tagsCloud.png b/TagsCloudContainer/output/tagsCloud.png index c5ee0316e4cf4737429c2c781af5f0f112a7b8ec..4e97d882efb63387fe268fd2428d078faa97486e 100644 GIT binary patch literal 27950 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 literal 23890 zcmeIa3s{qPwl5sVJ)3rS3f;SVrZ)lGYH7Xn28bj=?9g2aXlS93f&%SPp@0P|kVpba z9H&D&pSKe60)}*sUYJGa!auJi5dP`ZL;nm{ zjxYGrVfb25nYr%wgf7)0EBx_K#cynQgFyId|0Dhnehq&=ygfCyl0XPQkNz*XSn=f+ z0%4Pd^5z@w?kt!H?EQEJr6Del-M`|A^uK9NEm`sK9Zt3@n78Rw6A{omI9%JS)# zU#~xsxA^n51)q<q0(mrcWsqF!S@@Ya$i)AOp3+Aw8SsrS!2aZX zLn9xUv59eV{x=E(YrhjIqOg0el-BxxikE51Gb*d=x|{ZwGS#>vEUieOWilFhALmv*q~I;_P&4_e3|^~=+Mv7sFn;F`RWqi{Hfnk! zapmziXFJuBguXI`ZE5^NS4&OyX{;G{LrlF>wALKsaA$`x z8=u|T?UrxquE9+)-6yHx>uY*!;<2Glax*?Z^4Ak@b5^C7lI>T0M(U-|FV!;dVZ6Nqa9cT?hmhOq1RCLVlUe^YJRlNMDm- z{MNRjo-B(b&N{N*uKpF)>c)X^kdfoQ-OXt;SsGc`Oa}#Y=4ioOb#eR;3!yHe*!Pnp!;RWxjLc)Y zh2G)6uxw}cX!@5@VD`qmWhp?8}0!@a&EKP`jlp^wd_;3|t^_un($mD~>1|$C zP0eakt-$Z4Xx{K2DPNVIsc4f)O((~)?cOSyK{O(=7D<*>&(9j4`~TW!|7FGRO?J}2 z3s`ekeeK2bpE_rn@ZO>)BO{(4xK)M^y1y}OF@9ZqYr#W!`|+Iw{HC86#lpN-4L7RKD5Nce5=IN&|08=QMnOo z$$eCmG96bz$rK~mxNR-qNmpjux}klhy-KS42p`Aqa>6D=H9cChbx%$}zh-!N82`~H z!TFeDvT^I;Gjd4K2#JSEMJ?`zA2i1VJ|00%gkgNaTxm-uJ;zg zsPE77X#M5*P(Rb(^lhWJIdpP#xma>kN@LJ~T83MO z5A%hb`f=b!X_gn!7AT8s1;%`(D4VQwBGaBgIPzX(m%4~%qZ&8DWzMSRc2+e5>+Lt# z{heXSI@%;?9aZ{pol`NpUKGeu7mt4<~8?m7fp2?}7C>h`# zWlU!=4q>0a#csT>wS5sNZRzTrSZyTP6H1D&?9*f`$g2(2AC&3hSW|Pdslk#$a0#TS$E}1dGB;7V^tZ_jz^A) z%H_%UJ`Zdno@!|uvA#q>I?L^7p;iE|dWH$6;;8oxb8mSDSmS2T2hayRCXvsi~7#!j3U+quZtmMCE+p z#CvvKjcrekk(j~1N_hfX_JSSWx0yXOOHXWbd^J14sP~YlPPA6pIiLnW25D|vH_nT_ z#-xJ=vmg* zZ%$EqDS_8wGrTnS)lOD*;8F*N=xi_G)6g9G)A)`o^}H_?f-*g-i;m^_(5Z$jkG$$4 z$rez2%_9^!&7$v6G|_~0*tmD*CLJ>=_jMaiKX13+PO~|-#5FGkf+l@|T~(y~@i^A$ z7TU7uZN@|SC5%IG7Nqwyq0WE4t$w$yiDdeCe^Ztror#Kl|In;35f7R$={j$0Srg`+jEgHJt-pPn*# zkx+&VNod*Ph;P4+pZ$tU)(>W2=VM4D65laY-qgD(w;G*bg-RZYgcEzmvFJ}~dXZ!~ z)}~dq!%`sO53k4tSzFGaV{Jw^>vp^N=Uv09ZD96oRIUS^_&3p<-WmX@^j|V2;j?{+ z5q@r5b(T?G*M^;>X@P@af5r;E8}A>fqlUAU4;3&j$VKDJtHqA4G0MnMIA-ibxw%6y z#=sAE#RYzfOB(CQ&o9J|O94eD0X>-Ye@jTFsVfD8uU$KL(kFQe8<0Pj5&jJf2-&l6 z_(O}0(&34HsKxy8>8C)8;s8pUTWF@;O?K&R&P^E&%$0hoFdZy?q&u6DB%GAa+cdZW zaUBm#o$nF^eFJ~??h@y4EEgWIpJehEsyBA%NRT;oDT^2|wFvD$*E z<(U`B0j~R}*Q{Jg!84W1jGM1q5(SzXbz(y)wKahJfvmas7!4cTu|S$_|IK2T1k-5A zdBoc{hTs&vbIE8zMkuebyRvbMP^&W`->i9wr|2eY_9z+zA$n!x4#ybC(~>^z@CG

Mo%y^d}OEudz@ki$^3r4oKyXxy1r~1v?U-}-A#;k!|QP8>b7h5 zF1DphUPG#sPOOb2W0M;_-j<>|v_;qpo@0Wi*bQt`Dpbr%U5XEvwJECHUX=}YQ9XtZ+Kxg?yB0A-{CHu0g{@Ns=3zYY2NRl?&gXNllg$ya8qsTQ0tiA)vX2cr8tFDCAz5u~JTT>(CSnen)=NjW}I z{uUZV54oAo{I0+gwHdho5_T82xAyU)RvCiZVybEFMQ)<3`RcYDeYss-B&0gBWhC%h zmV@MYF-H}a-L2beEkvxNK$!a?D+f8%TG0Lna(fIM<+Eudg+bys# zlHqo}+~!}V)O(7+MIE8I502T0*dvP)(a1rt(!uGS-9|SIC6)C~gQmI$M~5z#Pm=_< z(YKz7eQ<4#6&r_Fv`A7!e=&&?ALPQEte_goc<$`Ht-jcwu5)P!*2#<3B&N z%iTe0&hELMr5vliR=HIugWc?%1_L?Q<4|>s*q=H%c3k(7wW}+p=Q^&BE^2mFW*jbB zsW+;Q*s4rf;OF;XERcnq$(6@>x%`Co*b{I9zpT7aCCNQZ+>CWL`W|t+X+tAX*q-A) zL8tR3s-z=wo6xjOzpbE{k=drANaIMDD1mopTX0i2;4pUv*V8MPR%c|M9Lu+#+_AOS zpmTHzq%;aL4-tEVM@m7|x#Zi%us=Gb-koNlQ<-Ef&J^z*Zlqs?{;|nRc4)-LYz2js z6e}~%d!ekRs+H~Xrt($Tyx4t=sBpGTzRP*D5*tPB9~n_a18&n`ER`(8d5~LiS9Sgh z!}QF~w*tph$)cEitnUiX4_Bw}`Oe#~>vwII7KlCXw#U9ek+*CSF057fa*Y`6!St^1 z$Z-$9s$>;dtS{+H!~KgqZYid91}}GoM~!=0K=_WS$}EoG%pA2@&R~Z1=xemF0}x0U z&*94?SF@e->@s*~_a7m8vA5_Su8PL>os4*yl)coW#X~yWP_<|AO&c?QJYQ+^XydF; zW1BM=k}?l$ua-A?x{5r$lBOzbn1oSIep2dLX@QbSlZeJ+TF&C4;!6MFGIVTbR^!2% znZI{ME!mVWE|SZ@%m0TS`B!ZHGTWwnoXFW)yu%{N2~}C~Duop1$?dcF@btN$-Nmmr zDY5Z!$qw5af7N?R^&&So)ce64#jgKPKU^gL_;Yxx=;cZN4>A2in0e27a~X}HBtu((R zZ!tn}tQjJNmtR!kQ~!dvSR~>a>>fP96BAAW~|$MV;EZt_Df-Zn%McBcT4qt zeeF8wIyiCcFe&p*$N1S1nRMW^q*wbCe|jCmi>Px8PelEW`0A3HpLxJ)xO*v(BSW56 zwEQ&2UD4yB@CzElQ|>=kDGug~Cng!KW*+zsy<58<92;p(fLPFHE`?Y~W~dRHh4?_Y zg05*DU#ZWI$ro&;jTk}QN!I%09|F5=gvi8>=j^>zCD%?bx1Xu47ZzSz?%inb8q1#N zrJ3JqZW^dfRdQGw88D*|ZDXq932X--_(bgl9S?jmJ{z8)*hh2pjzFMB$61Q{b}er` zFU|(WZqKxogE3$JR!QKP*I2wrvksHsA_m%!V@xFX~NtPoxOESE3y$^FhIZa1}F0 zgCfvLvF&C=VjoY=dl_aiR^FhK@s7e=f4aqp9Y!-!!-`juGzBPjO`=ZIS=q*BdrQ?{ zD2iAHI*DNN#vul=E=j^}>gk-An5gOy(lPZhN=vOTy#J`f!CyW5bWHw}ZDzg}yrOI{ z@wBzVDP~?*rxbQ?DVVc-Y9l?bXnxl3XcoMOgb(88m-oq7B#oTab*$=HiXtTm7qED7 zs`nYKvdFwtegcUrYyntrEn9kNZE~>Tm}u)p4XI)8KQM;9nxq`Ga0-WzU7#5sK@k=B zJF-pAL(K=p4dLhVKqny^kbYx0og_r9&7+NG&&OUzl4+^@j0my;k}JoiMcrhKrTuBv zS3B=%n2SRNHj}cE_p<+=861nY;Bp49;1*^XgOM!K)Lp=PITZf)`@Kv!+DufigoY?j zuy;?9%%H_^hpF(n$hXfxXDGNc@vSjk{#tBI08zFw24X03EIz}1g%|$P#(M*vn1HqF z;u)dQ@2uV+6?Hb6ksG;ZZ+)@oWs7F+`aM?NTnsTDI)9?2>Sk}M!Yf2u%_VR4Ztt8f z%2%~{d+$$3WujWrMn1xp;e|j@j45!=rJ-ksDTgbqfsepl$OAuQ_$$d_;>zVELdzwX zhiEGCOGI*}TJvn`BYUXqbyVrGbZ5o={p8DaR`6NDFh7F^NlP`b1j&u9dG6XCo7>J6@J6?(Zwzo9WaqX{TX!i~sl5S5N)=tr*4gF+ZLO zY)uzv*=*asn{%y#i`f{-RN|IWB#4{ZNPN$Y&mFO232Ely`{N|BN`xmyta~y!zbTB7 zhwyc3t2(9o)drvOY}(KA%>9VVqba^Sgc__p7|zRkziN`yAYDnL%VhGGJsY`V zUh?kv*!Dtfa_tpAxMF-&rE&Q0iC98cm;S_>4%FXOWG4286IL)YwQp@ zpS`kNHdtqs7%JCEGcXUwpF&J6Ezx-R=y=;89pJsw00mNx#}&fto(|r+9f0_&h_7EXW7G&1Uv zGRf$Cze%Q=1ibRzkzD02^Ye8k8pi6J)G!J<=3C%wE?R2WfkKLUkmL$$Y#}|y+{g*X(Jycem=c%W6o=Miaa zPw#Y9iBVJsHu})xC5lf%XXc{p({IU0kQ!;DM!4cNmWl+5&4V5oB)9HvJtTwFUW2X- zk%otU7u?9)5B|q+BZMzW54);0#iz#J9C6-XkCluzRu3dv&_N2O+Dd=#RMcMNx(P|` z1Rj8NpogpBsAyuNwly~gWgoZ#TFO?u87grT+X)^tfbg_5Ov_V zM+n|lau&;x=C%E&gCHDB=d|qWd)`=#WkfIz>|1UWp>!Us!ksrqDi(}x^0}+f(0*Wo zpYI70S-KyVhoq@vKCnCl2ZeKDABb}orsB{BG2wx!2Udh|gBM)C0b+Q+MN}~1seI1v zMUr@bECW*(o9sS?3!uL@ceR#Z1`a~&O4wfLtMoL+S(&&%9j^NHT?ooxpMB9fVF2#BKzgygr`uB-QxuDkwA zyBdski$m_vGvSo1mes2RoJQ7(Zo?!$sJP>4?e^Mag~in#>2;6gB&RUX7;)=Gu zPm*%m*Fz6K#wsBBRo)v)LnJfQFRqO=0O7{;oYW=G_PUo`NA(f#rKoeORcL zTq(Bnsj~(`%WDjCfxqqE-{cKM;cD~L9O3rR`N8q}#p39ReZw{1?)dJruvl8ncRh|Z zgv8kd@`YoIxaPpqq&{D7gJZ@@R^PU!%)&@(OzyueJfN;o2m+Na-ucY?I2z%5M+09@ z%|oU)J~GwO9MNBMRO-s9uKMUCk-%J7qfmVJhVn>E)ELG$PZWiToV7DoHKEV!jA(}= zazV9}DUpz@F7^-uH(c6blmosu7o{x=I>bff0OO3SH4`Pkh#Q;n0Va7?gB zHR_BADcNqBt(axg`hrApp!rF+_qn-FFUcIU)goU#yZ%N^1*Wkd71keIX+O37B7fm* zi!tS#G1RT~ng82Nh0H5=Z{O;zORQ7IIK8U#yQgJe5mU>_!m7|gp0~t1kP&L}!@wmh zCog4+XXdr=<`M+cz>x#|0acM@fMLRh|NeR4AbyJ5rutyq`oSoC4wL_Nz?*T|ocK*} zf35m8Vc2n*)58~RKI2U`hM2SL&C`y+QL@@t|4@u~g6=d{P7`jsP0rzB%akR@-fs}g zv0UQXZeS$Gv(wf$#*Mo#=)E6L`plk;-Jz@j?-AZ^%kZ=1YEgaPalY3&aZXE4`go_m znbRWfckt9>L*v1IFUdK*=I-|Y=4myCHfA-J2XIld1W;IJe^L}X7j*mGn zX9=()=KWJ{!fie0&m7Bvp2+Y4`Zue|@86JzY_Cq~z0c(aenXGg!-(RpsXQWM3-Vfg zc_M**!Znk{X%VTf@Wd>Ox5&HT>zDzv#NhV{(nIeQT2$D14^SQb%?~b%!nmT8tA_%d zzxqdPiy4-=o!>=SCJnaXq__h4^ziOKWQokpMniv@$J51rS>SW~FBt;2E$+w7PQBOp z1{U_I{ZfB!GPZtf*0i~0^^q!OyX#QDUp?c$Jsz^{b}&=rj28p# zWOctmGB*cn=f1%rOdfT@>Hjq^^g9fg;`$^f;?b7G?kiqLjg9-UN8UMbff3}5ibA)q zs^;8Ro}J!T8){)J`o?@02B@*$4C~yNkm&y5+1E z;;S6{V^c@#A7j8i_A?2Sx&>3Vo&mRDij1f@YmBpHo(X@VYe*o_7Z+d2m4N?cc{fi{u2unw$Gq(Z1ydlH<<}U6!8OI?i(a{7R`Khv+;d(; z$~m=yBOx%u?tkxuqF_8dU+KS$=t9+_7kqW19<9 zxWm@Q%)X=uA?9*f>XaYQ2N-JA&EP%*Y&e79+c&YORvrF@pq6l&_&wV;-aiK0?luH; z#Y>L{a!;`dld~`c&RgSD|Mh1vB72MKThx(FmO1ZE!fBOo4WVZ8{!^;3#S*o;a3?`? zCAg+GKI%^xPe0)%v|c8Wmqu}qT@pKmTc!z1JSwo9qk4 z_@XC9td;h=v%XvKb-UlkPFq8m9XSRcy|sdv%3u?s$$dVGTUBEbZn2!25=E`A)f;Ly zu0!Q+;ofktdrz+Jm{n#L0xxFCuFar@wY%DZqd=|F2uvr$d_ALo{ zdEtRXY18$Hl|KlTt9>SJsl6F#Os8L!lHed`mhSeTDoUyLi8kJvu_L7;oAB}VLk)4Fe zXvuC%O!VUZ%QSgVKj+U1Ql?@5*~;QcL6OtoTky4o!!~X83~s+tScgBg64r3P{*5~s zp$uKEenAy0T4VTrIB|vIc(697&;lE8c5|&}#q-wjo(cbYa=`5_m#B-?g&h3(cO)s7 z71M+*J&MYQ{QLojU{GCnTqxhiI8w*4ma%PWH!14Xq`UECPav2ks$Xn+9u0Qqfw0BL z!B&_^`J<)o&cXw9#Z)!3g(H|WSceoTeb?QUz;Iq~q?k2rS$o-ZuGVCq?Q=4`YHz@5 zn2U_)#b&IYBy5Qz?<}t|EZACSX9QRNSqxII+ci6&SFZ{QcPD!-eZGWWw*)elCV7(U zOmq3((iV<3yICj0`3jqb z7^=C=e~s+6%w{_)1{g{QSP3kJ!Rh8jENz*M#iGsMzD`=>Z;n_y9saJu7T-G&^(4o> z@POPfz}e1TYGz!qaec4}P7cRVA4-ZTv}jFE{dk~*9A>`z6w;Dh@<;R;FK|_7L4{fr zS~91)`O#$uc~?*$v34Xt5C6s)s&xl0Oay*2S+2~Os~PYHlwRp2n0N+Daea+_Z%x20 z3FanyEQ`^ix;Spal4kiU@pEA#M$=Cpp`74>-ow^?=Bj==SWN<+UwLViRQ&5fHaC~VYv=Wg%%JFmuBj9Fp9S3%EC z%1wMyn9A%Wvb+jDY~H)`>o$vQzAt4>WOluQOpe3sZ-78R$z5z5DO^occu z;m@7kt{X|)f~K&=8-gPl7LW6JGos-7;*ysWA8>nH;KqPOHc1hCf{Nc_s%k|I;dI3` z_hx(l0(N+1`1WBhLU@OH>YE*Rh5$@PwBl_!H->h9qWh@t_3;zAmmw00(R5wpuX%5^l};nk z48`*xOakYdp_ET}j(hoO!pti%5zkSj%QH-PCTdi1Y|W>utzBzsUcrcPLpvrHf7dFT zye-EE8oWHT`_un9fuHNOoY4c=?y>p2uPcn7{O)S2So#Ab*#EIG;&+(}3|xWbV(>Ao zt+Jf^{m3xHjY;@IpRMxV{QXEX$_(Kbjxaq7QbwX7FtGpUw*nvg|8G8LdV;^5e8zvx z`AD)-mi&J?rPyY<(*4&`{$}>oofFm=itpxoF=LVanVI?N%tpm4GjUGeih=O~g1*A% z9?LghmO0S+zA}4~^FiRG`H9*lM&0ks)rDMJLZHUo<-CIt;2!p0Q=AGu(A8Q`bFjb0 z;GOK61MVA4XO9=Y#~JtjS}>L`_&dY+#21qmWs?_7OK!BaH~5LCmtE*8F?n)p4Rs5a zaZH^x=zyI0yes(ErY>)1D_edIk~7LndaBeU*&%hm$@xvcR`1*-O)lDchF6q?5Kj)* zeUdK)KB;GG1C7&(W&_45A)>0cu-+OzowR4R^iUz12>Xo8t5N;jX5s#4?DxLJ|e*uoJ}o z#cEauU-hB~ssaF4&gsy$l}7;8S{aFxdlEsw70Zpi!aOB!9?YHLey#RQ#$4_`G2^F{ zAyx7b9p-tpQ&0pMJ@e~%O7X-5px6114&E5Lf)u6Mp(@N7N5F5ICb&#r+M?r2dz)wg zsHWVk1jo>+8aDx~9T3B$$kBMAKq3U>P@@Qtaj_-BI}ek*Mr&M#C&#_SjxzCsy)yS< zJvO!__G7L0$Jr}jN?Z~!ktTkQT)WIGll7jiH1nzMcVUV<7--HW+r5#AbmR>^O)=F% z2f#BQ59H1qP4*O5TOM3Vt$J7sAU~aP&S;c1I1IdrDLPTv(c4tmCquA?ifYR%B8mf)Uwo_@fOjv`ZY?~wCm}ukkmxxTI$$0=u zT#n_NM^8HZTYC`VzP3tZrvrGu6@%Xs?dn!mkIM}UXZ>NOeDlllFiCCiR8uKPQv1yo zt#@*sICUBcXOSF0T30({5017|#O4dB3`89Ug>YE0O#to((GUJ%YG4mUOUr;oFJ)9) zdK~i{rK;e8c~SEp(n3h$l0c^De;v?zo%3DMr!y_ot}9YWZjY@CN)Q}yEDUbs2S2Gs z=rF2ugRK`t?<$oe1g5+EAr9I~NOxXD(6+Qj;!9*b-yj8Ce>)nH;y-)^f=eh4e>@H$ zeuN*Wtt@X9C!SpGWs_L#+R8hhIrJWca%SIgpa5}yw(pTLTy%vj05$8&K1$9xF zXiN_rJc?l*arRjj_@oCNn?vPdOrkH~iCHAHAig*tz1yE{m4A<98x#|y4=HpOS;;rZ z@6A&1a@~ICrO&!Us;ZLd(j%lgb&CVaH@c>~y0A)(W-B_kgq=2!-_hNQ`OZyH*^!`^WR(F7iK&KdUuoQSs5SVcL;ebb-ZgQfOz3{xSYt%s+)}`(xtQMn#t8;4Vh= zsn$6$I)T!Bfv4OZRce$xy960BganG;B6R8*Q(^=%hXk({CAvveZzd-J9wsc>d2vCy z)I#athcB@*gk#y(md%iTI|w-Iml&;cd!8lLiA_eQ#&iS{FK`%k01n7r)j=W|`NnQ7 zfC3PaZ99G3rAB9*o*LFLC5s(<*gAlSG(qC06p~I)V+OG6WXqbf>%BJ6O-AeBB^i6a zrtTsPCLX%c-Dq^gV{XRi#-y6!wxGq=qAq;JSc1Bh-pWVTUpM z7Ky1VU*oi(^y`)7n!tqz=ok~v_K)--02<&O!fWfNWVw>(!NL0vsrdm~GT!;ixr|k! z%wFM$bx_u3KF>#)B!sFOgFGOPFgL#(S%6M|Fecy}yYMb4a%Y;ajmj)^QnIkHme@V0}@q*Koa9Q~w!=#StkvT}nW*xH}Wi%@Ye+)@Zq zfcD|XqzR*YH8=fKNSp$f{ABzD*9+G7gUcX4x%VH(%}t<$x#PuY-bMeoj)aN>;djbf z4me1_xX&Qa(QAkZZkL-DM_w|ldDh5)y-XPUt(Cp`K2s3--yj~0b|0*A{@h^x+4?s7 z%Hx{4vY(m6qnf|?kHoajUHixF8hoZTWwr@6rtLqw2aH+ta}!LhpL{7s6Qn{a{l^C=#$vKVh4}XWGusidCR*e!3tlBEKPj4j@&?CH{1C9%)VS z(GUO$sz`qF*udMwPVx{S@lYc3#~eDCkXk>DW!y0q`}q%U^etX!-7I;w2NOs_#ne#5 zzp{O0p&>CAJSDJu?j8tg!)+W}nOHm?Bge8WgwguB_K2r!<37rKvzeQ0Tgsn&QnscH zC&WH0@E!QeK$l=@1nZd_?GPq!`SJ%6GY?r$$%TDV6QDxu`%1dH3Za^2d3&LFFW7K) zjS3+YF}^3vcr*)U5nh@`f(pk9fNscm0KRBr%jp12z%#}KMGo;v^3aE?%4~knhuDb< z2fL%Axl4GzNYpisiZfu1_aK-jOB#pS?s=;~0XYF+zvfVvEUO%a<{J?@v0 z^d&eVHTi<|*`0O+0ApLH@dG4YT&i$%jwwq`I;!pD7{xd|UjP|xS1p(+wUp+F_ap14 z1CR}+(3ouRCsvfkc)+N^R(152F_BPc-vsE{kLh=|Ah>vry94TWJ7b&o(wXg*F<3L# zUB@D>n2yl2tD*iFA;ssLRaVP8~XIKceJ(Z{sb+}PaZ4$=O4C_QS*>f~f zdzRQUK15~2V}MyM`FK>5bJ4MTM6sF+J`_IbgHTu32IX~KV|dp>-EQ~r%^FxeYEd<+ zu7+~3#*qv-Gp{Z;HXVgZN1=4Say0tp?Z?(YZEy@;ea)y&YB#pvB^ppZCDCT^4=u-0 z&V-p%>#IojzIJ@Lv)$bSdy0d*J9Jj7rW0WUJ0~2i7;p|BhN$(ti-+xdhPG|Eq(e81 zRarIAp|E4VhS;^dE#|3QiHL@|Cksdn~V>pcsH- zzNBA_v*u;8;*Hy`wdTrKjRAh~9R}+@^G2N_*1`i%4NO|58Vkpl>ztN^+6-(=P$)af zh_@tB&0cNr`zmjDNEw4!&|Y>M>OF*v8yiP>k(3IF{HgZsCfgMITb=Oojy*F`eq0 z-^|e`R@baPrIp8u4L;9uVPHNoG`Rn(%CGyhyAxYY}d1imBqKZOC9{3X)9K4lJLzCAA##IZ>GgjQp|ahW z0C?|U`^8yV2?aV3_Q|p_=e~*dJtI!W+xU z@b&|HRq_U3OTiG-lDup`15u6y1Qm-camJZ%PQ`cn#41#Ch}8{aF*R3u+ro3m5pOUS z^dbR6h4^%$;Dx#j@s>L(>R~#BA?CWSv<8i}JzBBCrXV^?U#W(u2{!mw=*$<-qDpY& zbH9vGq$(lBoCP7xi-6KxSAr&R@SP@v8bfF=ur*&Rv`&?YVH~m%neBvW#XK3y+uOl{ zjzv|Z%aCz~kx>HX91eq%nsRWO5RwNje1tGtAl|iYTCp5P10{@5gMnL7|DC_^?|4{) zhr9t8iS`Is*(h`apmGT500Zkx7A(c_r$XeQd1}!JVE3jJj+NP-_4;TqaL*=hf zWXK_a6B$PU1HQ8x&qocWXr7%|h6=fCSPA*abt`%f16SR9t_O%9l;q_`V?nl;iS@Sg z4dTuuN)M_M2bV?4o5q(K6Xes^)3J$S&wx2U**z7H%gx!BBBd<|2?>?(P-;YBk@y+B z0U?4ML4n>&O>jp6il(KTiY8&qq{C3Z4{RMOmHulh8Y1{OID z1GnE>K=+&2ptzyW!>>9a>w&5R?{x!v8Z)1>C?Kw_Knf2Kz?F^VtDb2Cd^}D9MMeRx zhe!YYHCBQg9r+ol-pJTIWT)NZ-p1}M*wF`?VF7Qb#B8gN#utY0UtMqW0BLNJ|Mef_ zuN7(RCMZEoHfA}USzb&$x$FE>yT||cF7mw?>V{ir6-IMIQwFaUhs_ZDY2*OGFH{U< zSOVCJjnaJ9uu-T+ts^>L!Dgh$Bof4i3&+yDPf8kmo)OTem5ob07ts3`psFyoXsfW0 zlyqE_D^FH+%@?sC*km&UDl)p@=p{jA1Puz~vKx%158>50*=Gc@rrG=?h4s{%cVja4)UE6?yrl3f$ z>g%hW3C(-qeAD(9jAKSoc`s%t5wbjkHPzp*8NUYgj(F_+B-lJusglZxuP7Bl3G?ID zf|r&<_|k00dKo;VU1%AJ27^Kk!DT2M#cCd}mRG#Xuz~Y%Omz{~^vmI|M%vx{aO{a2 zbmsS)=5DFr^?Ks`+8y_-iP^egDZt$>K?LVQ@#MbkOg9-3dfZqJ*8JfqOmZy zAV!l^`WDR%kJDxCH1HF!32nb_Jy!|u1cIz1ykw@CGGw0E1Xpae-Pg-XdoiPyP(a^7klRi`ih}Q; z3a^95aeM^X3s7f$r7=b($<2Z?-U%q|Jc*0W;kJd}gQtLC+4EcjwJb|W{CDi=a@5HK@AxaC)I~)@b&?p1#O2UdqGvO6Ar3#!)qCOA* z%MYA?`nt$wLhydjX9?-2wI!uu$RM>&V`bum(SNlPq*(3s@#1wO?S>1TP}d?QkL`mu$w zbNBP2m{WM;+SaMj`GP_G!v9&HXKxig>zs7V;SmPE`0lxjr0BQ%=Yse&Li_KY`PZ7$~!kkczVFG^e-PNgX=i4s7c$iwMHkUiwN!!y!1sf{Gq;C*#s|PDY}N` z9KrhtYdt@6C_hGqUU>sWwouvLWs%T;d0Dp8Rf z>Y!<~fCv}N!QJpCwQNkm$~maawn$QXjdavVsjS9a9Kz1sRj&%5+7(K!;Tb(B#cYXb zXaZGAVM{&uL~57^F=s2C1r^=#ezZcuZ zdCluOQ1vPqd=t^8VY`ZnQbnKvz~i|09v;_*MPoS6{md&#TtD+Rulvn##{A{;ffWeR zSlidaYI0xwK9JRX9*;6UaQ~N|zpTJ7EAYz-{IUZ7UtfV19pUxY7jB?j_hF6| Date: Thu, 25 Jan 2024 19:08:51 +0500 Subject: [PATCH 03/13] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20commandLineParser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TagsCloudContainer/CommandLineClient.cs | 26 ------------- TagsCloudContainer/GuiClient.cs | 26 ------------- .../Interfaces/IImageSettings.cs | 6 ++- TagsCloudContainer/Program.cs | 29 +++++++-------- TagsCloudContainer/TagsCloud/ImageSettings.cs | 10 ++++- TagsCloudContainer/TagsCloud/TagCloudApp.cs | 20 ++++------ TagsCloudContainer/TagsCloudContainer.csproj | 1 + .../Utility/CommandLineOptions.cs | 35 ++++++++++++++++++ TagsCloudContainer/output/tagsCloud.png | Bin 27950 -> 27117 bytes 9 files changed, 70 insertions(+), 83 deletions(-) delete mode 100644 TagsCloudContainer/CommandLineClient.cs delete mode 100644 TagsCloudContainer/GuiClient.cs create mode 100644 TagsCloudContainer/Utility/CommandLineOptions.cs diff --git a/TagsCloudContainer/CommandLineClient.cs b/TagsCloudContainer/CommandLineClient.cs deleted file mode 100644 index cafb59b54..000000000 --- a/TagsCloudContainer/CommandLineClient.cs +++ /dev/null @@ -1,26 +0,0 @@ -using TagsCloudContainer.Interfaces; - -namespace TagsCloudContainer -{ - public class CommandLineClient : ITagCloudClient - { - private readonly IFileReader _fileReader; - private readonly IPreprocessor _preprocessor; - private readonly ITagCloudGenerator _tagCloudGenerator; - private readonly IImageSettings _imageSettings; - - public CommandLineClient(IFileReader fileReader, IPreprocessor preprocessor, - ITagCloudGenerator tagCloudGenerator, IImageSettings imageSettings) - { - _fileReader = fileReader; - _preprocessor = preprocessor; - _tagCloudGenerator = tagCloudGenerator; - _imageSettings = imageSettings; - } - - public void Run() - { - //TODO: Логика для CLI - } - } -} diff --git a/TagsCloudContainer/GuiClient.cs b/TagsCloudContainer/GuiClient.cs deleted file mode 100644 index 2bd246c67..000000000 --- a/TagsCloudContainer/GuiClient.cs +++ /dev/null @@ -1,26 +0,0 @@ -using TagsCloudContainer.Interfaces; - -namespace TagsCloudContainer -{ - public class GuiClient : ITagCloudClient - { - private readonly IFileReader _fileReader; - private readonly IPreprocessor _preprocessor; - private readonly ITagCloudGenerator _tagCloudGenerator; - private readonly IImageSettings _imageSettings; - - public GuiClient(IFileReader fileReader, IPreprocessor preprocessor, - ITagCloudGenerator tagCloudGenerator, IImageSettings imageSettings) - { - _fileReader = fileReader; - _preprocessor = preprocessor; - _tagCloudGenerator = tagCloudGenerator; - _imageSettings = imageSettings; - } - - public void Run() - { - //TODO: Логика для GUI - } - } -} diff --git a/TagsCloudContainer/Interfaces/IImageSettings.cs b/TagsCloudContainer/Interfaces/IImageSettings.cs index 83980c41a..95519183c 100644 --- a/TagsCloudContainer/Interfaces/IImageSettings.cs +++ b/TagsCloudContainer/Interfaces/IImageSettings.cs @@ -7,7 +7,9 @@ public interface IImageSettings Color BackgroundColor { get; } Color FontColor { get; } Font GetFont(); - int ImageWidth { get; } - int ImageHeight { get; } + int ImageWidth { get; set; } + int ImageHeight { get; set; } + + void UpdateImageSettings(int width, int height); } } diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs index 247d5dfe6..343d4e143 100644 --- a/TagsCloudContainer/Program.cs +++ b/TagsCloudContainer/Program.cs @@ -1,24 +1,23 @@ -using Microsoft.Extensions.DependencyInjection; -using System.Drawing; +using CommandLine; +using Microsoft.Extensions.DependencyInjection; using TagsCloudContainer.TagsCloud; +using TagsCloudContainer.Utility; namespace TagsCloudContainer { public class Program { - static void Main(string[] args) + static void Main(string[] args) { - using (var serviceProvider = Startup.ConfigureServices()) - { - var tagCloudApp = serviceProvider.GetRequiredService(); - - tagCloudApp.Run("src/text.doc", // Исходный файл со словами - "src/boring_words.txt", // Файл со скучными словами - "Georgia", // Шрифт текста - Color.Black, // Цвет основного текста - Color.Red, // Цвет популярных слов - 0.2); // % Окрашивания популярных слов (топ-20%) - } - } + Parser.Default.ParseArguments(args) + .WithParsed(o => + { + using (var serviceProvider = Startup.ConfigureServices()) + { + var tagCloudApp = serviceProvider.GetRequiredService(); + tagCloudApp.Run(o); + } + }); + } } } diff --git a/TagsCloudContainer/TagsCloud/ImageSettings.cs b/TagsCloudContainer/TagsCloud/ImageSettings.cs index c42d3a1f8..635b26b07 100644 --- a/TagsCloudContainer/TagsCloud/ImageSettings.cs +++ b/TagsCloudContainer/TagsCloud/ImageSettings.cs @@ -7,13 +7,19 @@ public class ImageSettings : IImageSettings { public Color BackgroundColor { get; } = Color.White; public Color FontColor { get; } = Color.Black; - public int ImageWidth { get; } = 1600; - public int ImageHeight { get; } = 1200; + public int ImageWidth { get; set; } = 1600; + public int ImageHeight { get; set; } = 1200; public Font GetFont() { return new Font("Verdana", 20); } + public void UpdateImageSettings(int width, int height) + { + ImageWidth = width; + ImageHeight = height; + } + } } diff --git a/TagsCloudContainer/TagsCloud/TagCloudApp.cs b/TagsCloudContainer/TagsCloud/TagCloudApp.cs index 4b0205780..2b5e294ae 100644 --- a/TagsCloudContainer/TagsCloud/TagCloudApp.cs +++ b/TagsCloudContainer/TagsCloud/TagCloudApp.cs @@ -22,24 +22,20 @@ public void SetFontName(string fontName) _fontName = fontName; } - public void Run(string filePath, string boringWordsFilePath, string fontName, Color fontColor, Color highlightColor, double percentageToHighlight) + public void Run(CommandLineOptions options) { - SetFontName(fontName); + Color fontColor = Color.FromName(options.FontColor); + Color highlightColor = Color.FromName(options.HighlightColor); - var words = ReadFile(filePath); - var processedWords = _preprocessor.Process(words, boringWordsFilePath); + SetFontName(options.FontName); + _imageSettings.UpdateImageSettings(options.ImageWidth, options.ImageHeight); - Console.WriteLine("Processed words:\n"); + var words = ReadFile(options.TextFilePath); + var processedWords = _preprocessor.Process(words, options.BoringWordsFilePath); - foreach (var item in processedWords) - { - Console.WriteLine(item); - } - - var tagCloudImage = GenerateTagCloud(processedWords, fontName, fontColor, highlightColor, percentageToHighlight); + var tagCloudImage = GenerateTagCloud(processedWords, options.FontName, fontColor, highlightColor, options.PercentageToHighLight); tagCloudImage.Save(@"..\..\..\output\tagsCloud.png"); - Console.WriteLine("Tag cloud image saved to: /output/"); } private IEnumerable ReadFile(string filePath) diff --git a/TagsCloudContainer/TagsCloudContainer.csproj b/TagsCloudContainer/TagsCloudContainer.csproj index 15c0d36fa..2569f5f54 100644 --- a/TagsCloudContainer/TagsCloudContainer.csproj +++ b/TagsCloudContainer/TagsCloudContainer.csproj @@ -8,6 +8,7 @@ + diff --git a/TagsCloudContainer/Utility/CommandLineOptions.cs b/TagsCloudContainer/Utility/CommandLineOptions.cs new file mode 100644 index 000000000..92e73d7cb --- /dev/null +++ b/TagsCloudContainer/Utility/CommandLineOptions.cs @@ -0,0 +1,35 @@ +using CommandLine; + +namespace TagsCloudContainer.Utility +{ + public class CommandLineOptions + { + [Option('f', "font", Required = false, Default="Verdana", HelpText = "Font name")] + public string FontName { get; set; } + + [Option('c', "fontColor", Required = false, Default="Green", HelpText = "Font Color")] + public string FontColor { get; set; } + + [Option('a', "highlightColor", Required = false, Default = "Blue", HelpText = "Highlight Color")] + public string HighlightColor { get; set; } + + [Option('w', "width", Required = false, Default=1600, HelpText = "Image width")] + public int ImageWidth { get; set; } + + [Option('h', "height", Required = false, Default=1000, HelpText = "Image height")] + public int ImageHeight { get; set; } + + [Option('t', "textfile", Required = false, Default="src/text.txt", HelpText = "Path to the text file")] + public string TextFilePath { get; set; } + + [Option('b', "boringwordsfile", Required = false, Default = "src/boring_words.txt", HelpText = "Path to the boring words file")] + public string BoringWordsFilePath { get; set; } + + [Option('o', "output", Required = false, Default="output/tagsCloud.png", HelpText = "Output file path")] + public string OutputFilePath { get; set; } + + [Option('p', "percentageToHighlight", Required = false, Default=0.2, HelpText = "Percentage To Highlight popular words")] + public double PercentageToHighLight { get; set; } + + } +} diff --git a/TagsCloudContainer/output/tagsCloud.png b/TagsCloudContainer/output/tagsCloud.png index 4e97d882efb63387fe268fd2428d078faa97486e..0d4218c1e8934cf9d48edefcef77495c5ffe5335 100644 GIT binary patch literal 27117 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 From 40727672c058ba221b089acb24b1e9939c76e20c Mon Sep 17 00:00:00 2001 From: sibogatovr Date: Thu, 25 Jan 2024 19:11:36 +0500 Subject: [PATCH 04/13] fix --- TagsCloudContainer/Startup.cs | 1 - TagsCloudContainer/output/tagsCloud.png | Bin 27117 -> 29048 bytes 2 files changed, 1 deletion(-) diff --git a/TagsCloudContainer/Startup.cs b/TagsCloudContainer/Startup.cs index bbaa516b9..d11f0f96b 100644 --- a/TagsCloudContainer/Startup.cs +++ b/TagsCloudContainer/Startup.cs @@ -14,7 +14,6 @@ public static ServiceProvider ConfigureServices() .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton() .AddScoped(provider => { var fileReader = provider.GetRequiredService(); diff --git a/TagsCloudContainer/output/tagsCloud.png b/TagsCloudContainer/output/tagsCloud.png index 0d4218c1e8934cf9d48edefcef77495c5ffe5335..8494439ed86e2bd62ea31d6cebf5f324929f0fc4 100644 GIT binary patch literal 29048 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 d6W5+i2>8>5H=JVq(SAMNKm1 Date: Fri, 26 Jan 2024 00:39:14 +0500 Subject: [PATCH 05/13] fix tests --- TagsCloudContainer/TagsCloudContainer.csproj | 3 ++ TagsCloudContainer/src/empty.txt | 0 TagsCloudContainerTests/FileReaderTests.cs | 23 ++++++++++++++ TagsCloudContainerTests/ProgramTests.cs | 31 ------------------- ...eprocessor.cs => WordPreprocessorTests.cs} | 27 +++++++++++++--- 5 files changed, 48 insertions(+), 36 deletions(-) create mode 100644 TagsCloudContainer/src/empty.txt delete mode 100644 TagsCloudContainerTests/ProgramTests.cs rename TagsCloudContainerTests/{WordPreprocessor.cs => WordPreprocessorTests.cs} (56%) diff --git a/TagsCloudContainer/TagsCloudContainer.csproj b/TagsCloudContainer/TagsCloudContainer.csproj index 2569f5f54..42d4e4a63 100644 --- a/TagsCloudContainer/TagsCloudContainer.csproj +++ b/TagsCloudContainer/TagsCloudContainer.csproj @@ -23,6 +23,9 @@ Always + + Always + Always diff --git a/TagsCloudContainer/src/empty.txt b/TagsCloudContainer/src/empty.txt new file mode 100644 index 000000000..e69de29bb diff --git a/TagsCloudContainerTests/FileReaderTests.cs b/TagsCloudContainerTests/FileReaderTests.cs index 7b9c1d609..c9357c5f1 100644 --- a/TagsCloudContainerTests/FileReaderTests.cs +++ b/TagsCloudContainerTests/FileReaderTests.cs @@ -64,5 +64,28 @@ public void InvalidFilePath_ReturnsEmptyList() words.Should().NotBeNull().And.BeEmpty(); } + + [Test] + public void WithSpecificContent_ReturnsExpectedWords() + { + var filePath = "src/boring_words.txt"; + var content = "a an the"; + File.WriteAllText(filePath, content); + + var words = fileReader.ReadWords(filePath); + + words.Should().Contain("a", "an", "the"); + } + + [Test] + public void EmptyFile_ReturnsEmptyList() + { + var filePath = "src/empty.txt"; + File.WriteAllText(filePath, string.Empty); + + var words = fileReader.ReadWords(filePath); + + words.Should().BeEmpty(); + } } } diff --git a/TagsCloudContainerTests/ProgramTests.cs b/TagsCloudContainerTests/ProgramTests.cs deleted file mode 100644 index 10ff3d9dd..000000000 --- a/TagsCloudContainerTests/ProgramTests.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Moq; -using NUnit.Framework; -using TagsCloudContainer; -using TagsCloudContainer.Interfaces; - -namespace TagsCloudContainerTests -{ - [TestFixture] - public class ProgramTests - { - private Mock fileReaderMock; - private Mock preprocessorMock; - private Mock tagCloudGeneratorMock; - private Mock imageSettingsMock; - - private Program program; - - [SetUp] - public void SetUp() - { - //fileReaderMock = new Mock(); - //preprocessorMock = new Mock(); - //tagCloudGeneratorMock = new Mock(); - //imageSettingsMock = new Mock(); - - //program = new Program(fileReaderMock.Object, preprocessorMock.Object, tagCloudGeneratorMock.Object, imageSettingsMock.Object); - } - - - } -} diff --git a/TagsCloudContainerTests/WordPreprocessor.cs b/TagsCloudContainerTests/WordPreprocessorTests.cs similarity index 56% rename from TagsCloudContainerTests/WordPreprocessor.cs rename to TagsCloudContainerTests/WordPreprocessorTests.cs index 1c3bf5f1c..f7ae86da3 100644 --- a/TagsCloudContainerTests/WordPreprocessor.cs +++ b/TagsCloudContainerTests/WordPreprocessorTests.cs @@ -18,12 +18,9 @@ public void SetUp() [Test] public void WithCommonWords_RemovesCommonWords() { - var boringWords = new List { "the", "a" }; - preprocessor = new WordPreprocessor(boringWords); - var words = new[] { "the", "quick", "a", "fox", "jumps" }; - var processedWords = preprocessor.Process(words); + var processedWords = preprocessor.Process(words, "src/boring_words.txt"); processedWords.Should().HaveCount(3); processedWords.Should().NotContain("a"); @@ -35,10 +32,30 @@ public void WithUpperCase_ConvertsToLowercase() { var words = new[] { "Word1", "Word2", "Word3" }; - var processedWords = preprocessor.Process(words); + var processedWords = preprocessor.Process(words, "src/boring_words.txt"); processedWords.Should().BeEquivalentTo("word1", "word2", "word3"); } + + [Test] + public void WithEmptyWordsList_ReturnsEmptyList() + { + var words = new List(); + + var processedWords = preprocessor.Process(words, "src/boring_words.txt"); + + processedWords.Should().BeEmpty(); + } + + [Test] + public void WithEmptyBoringWordsFile_ReturnsOriginalWords() + { + var words = new[] { "apple", "orange", "banana" }; + + var processedWords = preprocessor.Process(words, "src/empty.txt"); + + processedWords.Should().BeEquivalentTo(words); + } } } From d7d53fd994ecd687133cfe17eb6964e88ebaaa8f Mon Sep 17 00:00:00 2001 From: sibogatovr Date: Tue, 30 Jan 2024 21:03:27 +0500 Subject: [PATCH 06/13] =?UTF-8?q?refactor:=20=D0=A0=D0=B0=D0=B7=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D1=82=D0=B2=D0=B5?= =?UTF-8?q?=D1=82=D1=81=D1=82=D0=B2=D0=B5=D0=BD=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B8=20=D0=B2=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=B5=20DocRea?= =?UTF-8?q?der,=20TagCloudApp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TagsCloudContainer/Enums/FileType.cs | 9 ++ TagsCloudContainer/Readers/DocReader.cs | 16 +-- TagsCloudContainer/Readers/FileReader.cs | 50 ++++++++ TagsCloudContainer/Startup.cs | 31 ++--- .../TagsCloud/CircularCloudLayouter.cs | 15 ++- TagsCloudContainer/TagsCloud/ColorHelper.cs | 12 ++ TagsCloudContainer/TagsCloud/TagCloudApp.cs | 120 ++++++++++++------ .../Utility/CommandLineOptions.cs | 4 +- TagsCloudContainer/Utility/Visualizer.cs | 9 -- TagsCloudContainer/output/23-tagsCloud.png | Bin 0 -> 29386 bytes TagsCloudContainer/output/tagsCloud.png | Bin 29048 -> 0 bytes TagsCloudContainer/src/text.txt | 1 + 12 files changed, 186 insertions(+), 81 deletions(-) create mode 100644 TagsCloudContainer/Enums/FileType.cs create mode 100644 TagsCloudContainer/Readers/FileReader.cs create mode 100644 TagsCloudContainer/TagsCloud/ColorHelper.cs create mode 100644 TagsCloudContainer/output/23-tagsCloud.png delete mode 100644 TagsCloudContainer/output/tagsCloud.png diff --git a/TagsCloudContainer/Enums/FileType.cs b/TagsCloudContainer/Enums/FileType.cs new file mode 100644 index 000000000..9f38271cf --- /dev/null +++ b/TagsCloudContainer/Enums/FileType.cs @@ -0,0 +1,9 @@ +namespace TagsCloudContainer.Enums +{ + public enum FileType + { + Doc, + Docx, + Txt + } +} diff --git a/TagsCloudContainer/Readers/DocReader.cs b/TagsCloudContainer/Readers/DocReader.cs index 95309f3a4..733863ef2 100644 --- a/TagsCloudContainer/Readers/DocReader.cs +++ b/TagsCloudContainer/Readers/DocReader.cs @@ -8,27 +8,21 @@ public class DocReader : IFileReader { public IEnumerable ReadWords(string filePath) { - var words = new List(); - try { var document = new Document(); document.LoadFromFile(filePath); - foreach (Section section in document.Sections) - { - foreach (Paragraph paragraph in section.Paragraphs) - { - words.AddRange(paragraph.Text.Split(' ', StringSplitOptions.RemoveEmptyEntries)); - } - } + return document.Sections + .Cast

() + .SelectMany(section => section.Paragraphs.Cast()) + .SelectMany(paragraph => paragraph.Text.Split(' ', StringSplitOptions.RemoveEmptyEntries)); } catch (Exception ex) { Console.WriteLine($"Error reading .doc file: {ex.Message}"); + return Enumerable.Empty(); } - - return words; } } } diff --git a/TagsCloudContainer/Readers/FileReader.cs b/TagsCloudContainer/Readers/FileReader.cs new file mode 100644 index 000000000..d01752a91 --- /dev/null +++ b/TagsCloudContainer/Readers/FileReader.cs @@ -0,0 +1,50 @@ +using System.IO; +using TagsCloudContainer.Enums; +using TagsCloudContainer.Interfaces; +using TagsCloudContainer.Readers; + +namespace TagsCloudContainer.TagsCloud +{ + public class FileReader + { + public IEnumerable ReadFile(string filePath) + { + var fileReader = GetFileReader(filePath); + return fileReader.ReadWords(filePath); + } + + private IFileReader GetFileReader(string filePath) + { + FileType fileType = GetFileType(filePath); + + switch (fileType) + { + case FileType.Doc: + return new DocReader(); + case FileType.Docx: + return new DocxReader(); + case FileType.Txt: + return new TxtReader(); + default: + throw new InvalidOperationException("Unsupported file extension"); + } + } + + private FileType GetFileType(string filePath) + { + string fileExtension = Path.GetExtension(filePath)?.ToLower(); + + switch (fileExtension) + { + case ".doc": + return FileType.Doc; + case ".docx": + return FileType.Docx; + case ".txt": + return FileType.Txt; + default: + throw new InvalidOperationException("Unsupported file extension"); + } + } + } +} diff --git a/TagsCloudContainer/Startup.cs b/TagsCloudContainer/Startup.cs index d11f0f96b..f772d26a5 100644 --- a/TagsCloudContainer/Startup.cs +++ b/TagsCloudContainer/Startup.cs @@ -10,21 +10,22 @@ public class Startup public static ServiceProvider ConfigureServices() { return new ServiceCollection() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddScoped(provider => - { - var fileReader = provider.GetRequiredService(); - var preprocessor = provider.GetRequiredService(); - var tagCloudGenerator = provider.GetRequiredService(); - var imageSettings = provider.GetRequiredService(); - + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddScoped(provider => + { + var fileReader = provider.GetRequiredService(); + var preprocessor = provider.GetRequiredService(); + var tagCloudGenerator = provider.GetRequiredService(); + var imageSettings = provider.GetRequiredService(); + var fReader = provider.GetRequiredService(); - return new TagCloudApp(preprocessor, imageSettings); - }) - .BuildServiceProvider(); - } + return new TagCloudApp(preprocessor, imageSettings, fReader); + }) + .BuildServiceProvider(); + } } } diff --git a/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs b/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs index e75263f22..3f21a1537 100644 --- a/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs +++ b/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs @@ -35,12 +35,21 @@ public Rectangle PutNextRectangle(string word, Font font) return PutNextRectangle(textSize); } + private const int MinPositiveValue = 1; private Size MeasureTextSize(string text, Font font) { - using (var temporaryBitmap = new Bitmap(1, 1)) - using (var temporaryGraphics = Graphics.FromImage(temporaryBitmap)) + // размер минимального временного изображения для измерения текста + var imageSizeForTextMeasurement = new Size(MinPositiveValue, MinPositiveValue); + + // временное изображение с заданным размером + using (var temporaryBitmap = new Bitmap(imageSizeForTextMeasurement.Width, imageSizeForTextMeasurement.Height)) { - return Size.Ceiling(temporaryGraphics.MeasureString(text, font)); + using (var temporaryGraphics = Graphics.FromImage(temporaryBitmap)) + { + var textSize = Size.Ceiling(temporaryGraphics.MeasureString(text, font)); + + return textSize; + } } } diff --git a/TagsCloudContainer/TagsCloud/ColorHelper.cs b/TagsCloudContainer/TagsCloud/ColorHelper.cs new file mode 100644 index 000000000..c589f5310 --- /dev/null +++ b/TagsCloudContainer/TagsCloud/ColorHelper.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TagsCloudContainer.TagsCloud +{ + public class ColorHelper + { + } +} diff --git a/TagsCloudContainer/TagsCloud/TagCloudApp.cs b/TagsCloudContainer/TagsCloud/TagCloudApp.cs index 2b5e294ae..03ea2d799 100644 --- a/TagsCloudContainer/TagsCloud/TagCloudApp.cs +++ b/TagsCloudContainer/TagsCloud/TagCloudApp.cs @@ -1,7 +1,7 @@ using System.Drawing; using TagsCloudContainer.Interfaces; using TagsCloudContainer.Utility; -using TagsCloudContainer.Readers; +using System.IO; namespace TagsCloudContainer.TagsCloud { @@ -9,14 +9,20 @@ public class TagCloudApp { private readonly IPreprocessor _preprocessor; private readonly IImageSettings _imageSettings; + private readonly FileReader _fileReader; private string _fontName; + private string outputDirectory = @"..\..\..\output"; + private const double DefaultAngleStep = 0.02; + private const double DefaultRadiusStep = 0.04; - public TagCloudApp(IPreprocessor preprocessor, IImageSettings imageSettings) + public TagCloudApp(IPreprocessor preprocessor, IImageSettings imageSettings, FileReader fileReader) { _preprocessor = preprocessor; _imageSettings = imageSettings; + _fileReader = fileReader; } + public void SetFontName(string fontName) { _fontName = fontName; @@ -24,41 +30,43 @@ public void SetFontName(string fontName) public void Run(CommandLineOptions options) { - Color fontColor = Color.FromName(options.FontColor); - Color highlightColor = Color.FromName(options.HighlightColor); - - SetFontName(options.FontName); - _imageSettings.UpdateImageSettings(options.ImageWidth, options.ImageHeight); + SetFontAndImageSettings(options.FontName, options.ImageWidth, options.ImageHeight); - var words = ReadFile(options.TextFilePath); + var words = _fileReader.ReadFile(options.TextFilePath); var processedWords = _preprocessor.Process(words, options.BoringWordsFilePath); + var uniqueWordCount = CountUniqueWords(processedWords); + + var (fontColor, highlightColor) = GetColors(options.FontColor, options.HighlightColor); var tagCloudImage = GenerateTagCloud(processedWords, options.FontName, fontColor, highlightColor, options.PercentageToHighLight); - tagCloudImage.Save(@"..\..\..\output\tagsCloud.png"); + SaveTagCloudImage(tagCloudImage, outputDirectory, uniqueWordCount); } - private IEnumerable ReadFile(string filePath) + private (Color fontColor, Color highlightColor) GetColors(string fontColorName, string highlightColorName) { - var fileReader = GetFileReader(filePath); - return fileReader.ReadWords(filePath); + return (Color.FromName(fontColorName), Color.FromName(highlightColorName)); } - private IFileReader GetFileReader(string filePath) + private void SetFontAndImageSettings(string fontName, int imageWidth, int imageHeight) { - string fileExtension = Path.GetExtension(filePath)?.ToLower(); + SetFontName(fontName); + _imageSettings.UpdateImageSettings(imageWidth, imageHeight); + } - switch (fileExtension) - { - case ".doc": - return new DocReader(); - case ".docx": - return new DocxReader(); - case ".txt": - return new TxtReader(); - default: - throw new InvalidOperationException("Unsupported file extension"); - } + public void SaveTagCloudImage(Bitmap tagCloudImage, string outputDirectory, int uniqueWordCount) + { + var outputFileName = $"{uniqueWordCount}-tagsCloud.png"; + var outputPath = Path.Combine(outputDirectory, outputFileName); + tagCloudImage.Save(outputPath); + + Console.WriteLine($"Tag cloud image saved to {outputPath}. Original word count: {uniqueWordCount}"); + } + + private int CountUniqueWords(IEnumerable words) + { + var uniqueWords = new HashSet(words, StringComparer.OrdinalIgnoreCase); + return uniqueWords.Count; } private Bitmap GenerateTagCloud(IEnumerable words, string fontName, Color fontColor, Color highlightColor, double percentageToHighlight) @@ -67,17 +75,37 @@ private Bitmap GenerateTagCloud(IEnumerable words, string fontName, Colo var uniqueWords = new HashSet(); var wordFrequencies = CalculateWordFrequencies(words); - var mostPopularWord = wordFrequencies.OrderByDescending(pair => pair.Value).FirstOrDefault().Key; + var mostPopularWord = GetMostPopularWord(wordFrequencies); + + var sortedWords = SortWordsByFrequency(words, wordFrequencies); + + var fontSizes = CalculateAndPutRectangles(layouter, sortedWords, uniqueWords, wordFrequencies, mostPopularWord, fontName); + + var rectangles = layouter.Rectangles.ToList(); + + return Visualizer.VisualizeRectangles(rectangles, uniqueWords, _imageSettings.ImageWidth, _imageSettings.ImageHeight, + fontSizes, _fontName, fontColor, highlightColor, percentageToHighlight, wordFrequencies: wordFrequencies); + } + + private string GetMostPopularWord(Dictionary wordFrequencies) + { + return wordFrequencies.OrderByDescending(pair => pair.Value).FirstOrDefault().Key; + } - var sortedWords = words.OrderByDescending(word => wordFrequencies[word]); + private IEnumerable SortWordsByFrequency(IEnumerable words, Dictionary wordFrequencies) + { + return words.OrderByDescending(word => wordFrequencies[word]); + } + private List CalculateAndPutRectangles(CircularCloudLayouter layouter, IEnumerable sortedWords, HashSet uniqueWords, Dictionary wordFrequencies, string mostPopularWord, string fontName) + { var fontSizes = new List(); foreach (var word in sortedWords) { if (uniqueWords.Add(word)) { - var fontSize = CalculateFontSize(word, wordFrequencies, mostPopularWord); + var fontSize = CalculateWordFontSize(word, wordFrequencies); fontSizes.Add(fontSize); var font = new Font(fontName, fontSize); @@ -85,12 +113,29 @@ private Bitmap GenerateTagCloud(IEnumerable words, string fontName, Colo } } - var rectangles = layouter.Rectangles.ToList(); + return fontSizes; + } - return Visualizer.VisualizeRectangles(rectangles, uniqueWords, _imageSettings.ImageWidth, _imageSettings.ImageHeight, - fontSizes, _fontName, fontColor, highlightColor, percentageToHighlight, wordFrequencies: wordFrequencies); + /// + /// Расчитывает размер шрифта для заданного слова на основе его частоты встречаемости. + /// + /// Строка, представляющая слово, для которого необходимо определить размер шрифта. + /// Словарь, содержащий частоту встречаемости каждого слова в тексте. + /// Размер шрифта для заданного слова. + + private const int BaseFontSize = 30; + private const int FontSizeMultiplier = 2; + private const int DefaultFontSize = 10; + private int CalculateWordFontSize(string word, Dictionary wordFrequencies) + { + if (wordFrequencies.TryGetValue(word, out var frequency)) + { + return Math.Max(BaseFontSize, BaseFontSize + frequency * FontSizeMultiplier); + } + return DefaultFontSize; } + private Dictionary CalculateWordFrequencies(IEnumerable words) { var wordFrequencies = new Dictionary(); @@ -104,20 +149,11 @@ private Dictionary CalculateWordFrequencies(IEnumerable wor return wordFrequencies; } - private CircularCloudLayouter CreateLayouter() + private CircularCloudLayouter CreateLayouter(double angleStep = DefaultAngleStep, double radiusStep = DefaultRadiusStep) { var center = new Point(_imageSettings.ImageWidth / 2, _imageSettings.ImageHeight / 2); - var spiral = new Spiral(center, 0.02, 0.04); + var spiral = new Spiral(center, angleStep, radiusStep); return new CircularCloudLayouter(center, spiral); } - - private int CalculateFontSize(string word, Dictionary wordFrequencies, string mostPopularWord) - { - if (wordFrequencies.TryGetValue(word, out var frequency)) - { - return Math.Max(30, 30 + frequency * 2); - } - return 10; - } } } diff --git a/TagsCloudContainer/Utility/CommandLineOptions.cs b/TagsCloudContainer/Utility/CommandLineOptions.cs index 92e73d7cb..26f619fc5 100644 --- a/TagsCloudContainer/Utility/CommandLineOptions.cs +++ b/TagsCloudContainer/Utility/CommandLineOptions.cs @@ -1,4 +1,5 @@ using CommandLine; +using System.ComponentModel.DataAnnotations; namespace TagsCloudContainer.Utility { @@ -29,7 +30,8 @@ public class CommandLineOptions public string OutputFilePath { get; set; } [Option('p', "percentageToHighlight", Required = false, Default=0.2, HelpText = "Percentage To Highlight popular words")] - public double PercentageToHighLight { get; set; } + public double PercentageToHighLight { get; set; } + } } diff --git a/TagsCloudContainer/Utility/Visualizer.cs b/TagsCloudContainer/Utility/Visualizer.cs index 6400afd68..0e781da9a 100644 --- a/TagsCloudContainer/Utility/Visualizer.cs +++ b/TagsCloudContainer/Utility/Visualizer.cs @@ -35,15 +35,6 @@ private static List GetMostPopularWords(HashSet uniqueWords, dou return uniqueWords.OrderByDescending(word => wordFrequencies[word]).Take(countToHighlight).ToList(); } - //private static void DrawRectangles(IEnumerable rectangles, Graphics graphics) - //{ - // var pen = new Pen(Color.Green); - // foreach (var rect in rectangles) - // { - // graphics.DrawRectangle(pen, rect); - // } - //} - public static void SaveBitmap(Bitmap bitmap, string fileName, string pathToDirectory) { EnsureDirectoryExists(pathToDirectory); diff --git a/TagsCloudContainer/output/23-tagsCloud.png b/TagsCloudContainer/output/23-tagsCloud.png new file mode 100644 index 0000000000000000000000000000000000000000..ee51b16b7af701a678150b8bb41030578394e512 GIT binary patch literal 29386 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 Date: Tue, 30 Jan 2024 21:04:03 +0500 Subject: [PATCH 07/13] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CircularCloudLayouterTests.cs | 152 ++++++++++++++++++ .../CommandLineOptionsTests.cs | 48 ++++++ TagsCloudContainerTests/SpiralTests.cs | 33 ++++ .../WordPreprocessorTests.cs | 1 + 4 files changed, 234 insertions(+) create mode 100644 TagsCloudContainerTests/CircularCloudLayouterTests.cs create mode 100644 TagsCloudContainerTests/CommandLineOptionsTests.cs create mode 100644 TagsCloudContainerTests/SpiralTests.cs diff --git a/TagsCloudContainerTests/CircularCloudLayouterTests.cs b/TagsCloudContainerTests/CircularCloudLayouterTests.cs new file mode 100644 index 000000000..46fa73367 --- /dev/null +++ b/TagsCloudContainerTests/CircularCloudLayouterTests.cs @@ -0,0 +1,152 @@ +using FluentAssertions; +using NUnit.Framework; +using System.Drawing; +using TagsCloudContainer.TagsCloud; +using TagsCloudContainer.Utility; + +namespace TagsCloudContainerTests +{ + public class CircularCloudLayouterTests + { + private CircularCloudLayouter sut; + private Point center = new(720, 720); + + [SetUp] + public void Setup() + { + center = new Point(720, 720); + var spiral = new Spiral(center, 0.02, 0.01); + sut = new CircularCloudLayouter(center, spiral); + } + + [Test] + public void Constructor_ShouldNotThrow() + { + Assert.DoesNotThrow(() => new CircularCloudLayouter(center, new Spiral(center, 0.02, 0.01))); + } + + [TestCase(-4, 16, TestName = "with negative rectangle width")] + [TestCase(77, -8, TestName = "with negative rectangle height")] + public void PutNextRectangle_InvalidSize_ThrowsArgumentException(int rectangleWidth, int rectangleHeight) + { + Assert.Throws(() => sut.PutNextRectangle(new Size(rectangleWidth, rectangleHeight))); + } + + [Test] + public void PutNextRectangle_ShouldReturnCorrectRectangleSize() + { + var rectangle = sut.PutNextRectangle(new Size(8, 8)); + + rectangle.Size.Should().Be(new Size(8, 8)); + } + + [TestCase(10, TestName = "10 rectangles with maximum density")] + [TestCase(100, TestName = "100 rectangles with maximum density")] + [TestCase(200, TestName = "200 rectangles with maximum density")] + public void PutNextRectangle_RectanglesShouldHaveMaximumDensity(int rectanglesCount) + { + var center = new Point(0, 0); + var spiral = new Spiral(center, 0.02, 0.01); + var layouter = new CircularCloudLayouter(center, spiral); + var rectangleSize = new Size(10, 10); + + GenerateRectangles(layouter, rectangleSize, rectanglesCount); + + CheckDensity(layouter.Rectangles).Should().BeTrue(); + } + + private void GenerateRectangles(CircularCloudLayouter layouter, Size rectangleSize, int rectanglesCount) + { + for (int i = 0; i < rectanglesCount; i++) + { + layouter.PutNextRectangle(rectangleSize); + } + } + + private bool CheckDensity(IList rectangles) + { + double maxDistance = 0; + + foreach (var rect in rectangles) + { + var distance = Math.Sqrt(Math.Pow(rect.X - rect.Width / 2, 2) + Math.Pow(rect.Y - rect.Height / 2, 2)); + maxDistance = Math.Max(maxDistance, distance); + } + + var circleArea = Math.PI * Math.Pow(maxDistance, 2); + var rectanglesArea = rectangles.Sum(rect => rect.Width * rect.Height); + var density = rectanglesArea / circleArea; + var thresholdDensity = 1; + + return density <= thresholdDensity; + } + + [Test] + public void PutNextRectangle_FirstRectangle_ShouldHaveCenterAtLayoutCenter() + { + var rectangle = sut.PutNextRectangle(new Size(8, 8)); + + var expectedRectangleCenter = + new Point(rectangle.Left + rectangle.Width / 2, rectangle.Top + rectangle.Height / 2); + expectedRectangleCenter.Should().Be(center); + } + + [Test] + public void PutNextRectangle_TwoRectangles_SecondRectangleCenterShouldNotBeAtLayoutCenter() + { + sut.PutNextRectangle(new Size(8, 8)); + + var secondRectangle = sut.PutNextRectangle(new Size(6, 6)); + + var expectedRectangleCenter = new Point( + secondRectangle.Left + secondRectangle.Width / 2, + secondRectangle.Top + secondRectangle.Height / 2); + + expectedRectangleCenter.Should().NotBe(center); + } + + [Test] + public void PutNextRectangle_TwoRectangles_ShouldNotIntersect() + { + var firstRectangle = sut.PutNextRectangle(new Size(8, 8)); + + var secondRectangle = sut.PutNextRectangle(new Size(77, 77)); + + secondRectangle.IntersectsWith(firstRectangle).Should().BeFalse(); + } + + [TestCase(10, TestName = "10 rectangles WithNoIntersects")] + [TestCase(100, TestName = "100 rectangles WithNoIntersects")] + [TestCase(200, TestName = "200 rectangles WithNoIntersects")] + public void PutNextRectangle_GeneratesRectanglesWithoutIntersects(int rectanglesCount) + { + GenerateRectangles(rectanglesCount, new Size(10, 10)); + + Assert.IsFalse(HasIntersectedRectangles(sut.Rectangles)); + } + + private bool HasIntersectedRectangles(IList rectangles) + { + for (var i = 0; i < rectangles.Count - 1; i++) + { + for (var j = i + 1; j < rectangles.Count; j++) + { + if (rectangles[i].IntersectsWith(rectangles[j])) + { + return true; + } + } + } + + return false; + } + + private void GenerateRectangles(int count, Size rectangleSize) + { + for (var i = 0; i < count; i++) + { + sut.PutNextRectangle(rectangleSize); + } + } + } +} diff --git a/TagsCloudContainerTests/CommandLineOptionsTests.cs b/TagsCloudContainerTests/CommandLineOptionsTests.cs new file mode 100644 index 000000000..5ae781df9 --- /dev/null +++ b/TagsCloudContainerTests/CommandLineOptionsTests.cs @@ -0,0 +1,48 @@ +using CommandLine; +using NUnit.Framework; +using TagsCloudContainer.Utility; + +namespace TagsCloudContainerTests +{ + [TestFixture] + public class CommandLineOptionsTests + { + [Test] + public void ParsingWithValidArguments_ShouldSucceed() + { + var args = new[] { "-f", "Georgia", "-w", "1500", "-t", "src/text.txt" }; + + var parseResult = Parser.Default.ParseArguments(args); + + Assert.IsTrue(parseResult.Tag == ParserResultType.Parsed); + Assert.IsInstanceOf(parseResult.Value); + + var options = parseResult.Value; + + Assert.That(options.FontName, Is.EqualTo("Georgia")); + Assert.That(options.ImageWidth, Is.EqualTo(1500)); + Assert.That(options.TextFilePath, Is.EqualTo("src/text.txt")); + } + + [Test] + public void ParsingWithoutArguments_ShouldUseDefaultValues() + { + var args = Array.Empty(); + + var parseResult = Parser.Default.ParseArguments(args); + + Assert.IsTrue(parseResult.Tag == ParserResultType.Parsed); + Assert.IsInstanceOf(parseResult.Value); + + var options = parseResult.Value; + + + Assert.That(options.FontName, Is.EqualTo("Verdana")); + Assert.That(options.ImageWidth, Is.EqualTo(1600)); + Assert.That(options.TextFilePath, Is.EqualTo("src/text.txt")); + Assert.That(options.FontColor, Is.EqualTo("Green")); + } + + + } +} diff --git a/TagsCloudContainerTests/SpiralTests.cs b/TagsCloudContainerTests/SpiralTests.cs new file mode 100644 index 000000000..3a3b0548a --- /dev/null +++ b/TagsCloudContainerTests/SpiralTests.cs @@ -0,0 +1,33 @@ +using FluentAssertions; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TagsCloudContainer.Utility; + +namespace TagsCloudContainerTests +{ + public class SpiralTests + { + private Point center = new(250, 250); + + [Test] + public void Constructor_ShouldNotThrow_WithValidArguments() + { + Action constructorAction = () => new Spiral(center, 0.1, 0.2); + constructorAction.Should().NotThrow(); + } + + [TestCase(0, 0, TestName = "Constructor_ZeroStep_ThrowsArgumentException")] + [TestCase(-0.1, 0.2, TestName = "Constructor_NegativeAngleStep_ThrowsArgumentException")] + [TestCase(0.1, -0.2, TestName = "Constructor_NegativeRadiusStep_ThrowsArgumentException")] + public void Constructor_InvalidStepValues_ThrowsArgumentException(double angleStep, double radiusStep) + { + Action constructorAction = () => new Spiral(center, angleStep, radiusStep); + constructorAction.Should().Throw(); + } + } +} diff --git a/TagsCloudContainerTests/WordPreprocessorTests.cs b/TagsCloudContainerTests/WordPreprocessorTests.cs index f7ae86da3..f14c7d69b 100644 --- a/TagsCloudContainerTests/WordPreprocessorTests.cs +++ b/TagsCloudContainerTests/WordPreprocessorTests.cs @@ -9,6 +9,7 @@ namespace TagsCloudContainerTests public class WordPreprocessorTests { private IPreprocessor preprocessor; + [SetUp] public void SetUp() { From 5e0054fae645b5fd20062e47b36389078e350430 Mon Sep 17 00:00:00 2001 From: sibogatovr Date: Wed, 31 Jan 2024 23:44:14 +0500 Subject: [PATCH 08/13] feat: add FontSizeCalculator --- .../TagsCloud/FontSizeCalculator.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 TagsCloudContainer/TagsCloud/FontSizeCalculator.cs diff --git a/TagsCloudContainer/TagsCloud/FontSizeCalculator.cs b/TagsCloudContainer/TagsCloud/FontSizeCalculator.cs new file mode 100644 index 000000000..0ca8abddb --- /dev/null +++ b/TagsCloudContainer/TagsCloud/FontSizeCalculator.cs @@ -0,0 +1,29 @@ + +public class FontSizeCalculator +{ + private const int BaseFontSize = 30; + private const int FontSizeMultiplier = 2; + private const int DefaultFontSize = 10; + + public int CalculateWordFontSize(string word, Dictionary wordFrequencies) + { + if (wordFrequencies.TryGetValue(word, out var frequency)) + { + return Math.Max(BaseFontSize, BaseFontSize + frequency * FontSizeMultiplier); + } + return DefaultFontSize; + } + + public Dictionary CalculateWordFrequencies(IEnumerable words) + { + var wordFrequencies = new Dictionary(); + + foreach (var word in words) + { + wordFrequencies.TryGetValue(word, out var frequency); + wordFrequencies[word] = frequency + 1; + } + + return wordFrequencies; + } +} \ No newline at end of file From 3f50bf8c0605e1d0aaa145f00754b1202604d4ba Mon Sep 17 00:00:00 2001 From: sibogatovr Date: Wed, 31 Jan 2024 23:48:54 +0500 Subject: [PATCH 09/13] refactor: improve property names and perform minor code cleanup --- .../Interfaces/IImageSettings.cs | 4 +- TagsCloudContainer/Program.cs | 2 +- TagsCloudContainer/Readers/TxtReader.cs | 3 +- .../TagsCloud/CircularCloudLayouter.cs | 15 +++--- TagsCloudContainer/TagsCloud/ColorHelper.cs | 12 ----- TagsCloudContainer/TagsCloud/ImageSettings.cs | 8 ++-- TagsCloudContainer/TagsCloud/TagCloudApp.cs | 47 +++++-------------- .../TagsCloud/TagCloudGenerator.cs | 2 +- 8 files changed, 29 insertions(+), 64 deletions(-) delete mode 100644 TagsCloudContainer/TagsCloud/ColorHelper.cs diff --git a/TagsCloudContainer/Interfaces/IImageSettings.cs b/TagsCloudContainer/Interfaces/IImageSettings.cs index 95519183c..7dd42a9ca 100644 --- a/TagsCloudContainer/Interfaces/IImageSettings.cs +++ b/TagsCloudContainer/Interfaces/IImageSettings.cs @@ -7,8 +7,8 @@ public interface IImageSettings Color BackgroundColor { get; } Color FontColor { get; } Font GetFont(); - int ImageWidth { get; set; } - int ImageHeight { get; set; } + int Width { get; set; } + int Height { get; set; } void UpdateImageSettings(int width, int height); } diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs index 343d4e143..d68b4a046 100644 --- a/TagsCloudContainer/Program.cs +++ b/TagsCloudContainer/Program.cs @@ -10,7 +10,7 @@ public class Program static void Main(string[] args) { Parser.Default.ParseArguments(args) - .WithParsed(o => + .WithParsed(o => { using (var serviceProvider = Startup.ConfigureServices()) { diff --git a/TagsCloudContainer/Readers/TxtReader.cs b/TagsCloudContainer/Readers/TxtReader.cs index d12633639..d0c75f157 100644 --- a/TagsCloudContainer/Readers/TxtReader.cs +++ b/TagsCloudContainer/Readers/TxtReader.cs @@ -8,7 +8,7 @@ public IEnumerable ReadWords(string filePath) { try { - string[] lines = File.ReadAllLines(filePath); + var lines = File.ReadAllLines(filePath); var words = lines.SelectMany(line => line.Split(' ')); @@ -18,7 +18,6 @@ public IEnumerable ReadWords(string filePath) } catch (Exception ex) { - Console.WriteLine($"Error reading file: {ex.Message}"); return Enumerable.Empty(); } diff --git a/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs b/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs index 3f21a1537..f75b40300 100644 --- a/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs +++ b/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs @@ -19,6 +19,10 @@ public CircularCloudLayouter(Point center, INextPointProvider pointProvider) public Point CloudCenter => center; public IList Rectangles => rectangles; + private const int MinPositiveValue = 1; + private const int MinWidth = 0; + private const int MinHeight = 0; + public Rectangle PutNextRectangle(Size rectangleSize) { ValidateRectangleSize(rectangleSize); @@ -34,8 +38,7 @@ public Rectangle PutNextRectangle(string word, Font font) var textSize = MeasureTextSize(word, font); return PutNextRectangle(textSize); } - - private const int MinPositiveValue = 1; + private Size MeasureTextSize(string text, Font font) { // размер минимального временного изображения для измерения текста @@ -55,7 +58,7 @@ private Size MeasureTextSize(string text, Font font) private void ValidateRectangleSize(Size rectangleSize) { - if (rectangleSize.Width <= 0 || rectangleSize.Height <= 0) + if (rectangleSize.Width <= MinWidth || rectangleSize.Height <= MinHeight) { throw new ArgumentException("Width and height of the rectangle must be greater than zero"); } @@ -78,14 +81,14 @@ private Rectangle CreateNewRectangle(Size rectangleSize) private Point GetUpperLeftCorner(Point rectangleCenter, Size rectangleSize) { - return new Point(rectangleCenter.X - rectangleSize.Width / 2, rectangleCenter.Y - rectangleSize.Height / 2); + var center = TagCloudApp.CalculateCenter(rectangleSize.Width, rectangleSize.Height); + return new Point(rectangleCenter.X - center.X, rectangleCenter.Y - center.Y); } private bool RectanglesIntersect(Rectangle newRectangle) { return rectangles.Any(rect => rect.IntersectsWith(newRectangle)); } - - + } } diff --git a/TagsCloudContainer/TagsCloud/ColorHelper.cs b/TagsCloudContainer/TagsCloud/ColorHelper.cs deleted file mode 100644 index c589f5310..000000000 --- a/TagsCloudContainer/TagsCloud/ColorHelper.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace TagsCloudContainer.TagsCloud -{ - public class ColorHelper - { - } -} diff --git a/TagsCloudContainer/TagsCloud/ImageSettings.cs b/TagsCloudContainer/TagsCloud/ImageSettings.cs index 635b26b07..7c4aca608 100644 --- a/TagsCloudContainer/TagsCloud/ImageSettings.cs +++ b/TagsCloudContainer/TagsCloud/ImageSettings.cs @@ -7,8 +7,8 @@ public class ImageSettings : IImageSettings { public Color BackgroundColor { get; } = Color.White; public Color FontColor { get; } = Color.Black; - public int ImageWidth { get; set; } = 1600; - public int ImageHeight { get; set; } = 1200; + public int Width { get; set; } = 1600; + public int Height { get; set; } = 1200; public Font GetFont() { @@ -17,8 +17,8 @@ public Font GetFont() public void UpdateImageSettings(int width, int height) { - ImageWidth = width; - ImageHeight = height; + Width = width; + Height = height; } } diff --git a/TagsCloudContainer/TagsCloud/TagCloudApp.cs b/TagsCloudContainer/TagsCloud/TagCloudApp.cs index 03ea2d799..6b970f0be 100644 --- a/TagsCloudContainer/TagsCloud/TagCloudApp.cs +++ b/TagsCloudContainer/TagsCloud/TagCloudApp.cs @@ -10,10 +10,13 @@ public class TagCloudApp private readonly IPreprocessor _preprocessor; private readonly IImageSettings _imageSettings; private readonly FileReader _fileReader; + private readonly FontSizeCalculator _fontSizeCalculator = new FontSizeCalculator(); + private string _fontName; private string outputDirectory = @"..\..\..\output"; private const double DefaultAngleStep = 0.02; private const double DefaultRadiusStep = 0.04; + private const int Half = 2; public TagCloudApp(IPreprocessor preprocessor, IImageSettings imageSettings, FileReader fileReader) { @@ -73,7 +76,7 @@ private Bitmap GenerateTagCloud(IEnumerable words, string fontName, Colo { var layouter = CreateLayouter(); var uniqueWords = new HashSet(); - var wordFrequencies = CalculateWordFrequencies(words); + var wordFrequencies = _fontSizeCalculator.CalculateWordFrequencies(words); var mostPopularWord = GetMostPopularWord(wordFrequencies); @@ -83,7 +86,7 @@ private Bitmap GenerateTagCloud(IEnumerable words, string fontName, Colo var rectangles = layouter.Rectangles.ToList(); - return Visualizer.VisualizeRectangles(rectangles, uniqueWords, _imageSettings.ImageWidth, _imageSettings.ImageHeight, + return Visualizer.VisualizeRectangles(rectangles, uniqueWords, _imageSettings.Width, _imageSettings.Height, fontSizes, _fontName, fontColor, highlightColor, percentageToHighlight, wordFrequencies: wordFrequencies); } @@ -105,7 +108,7 @@ private List CalculateAndPutRectangles(CircularCloudLayouter layouter, IEnu { if (uniqueWords.Add(word)) { - var fontSize = CalculateWordFontSize(word, wordFrequencies); + var fontSize = _fontSizeCalculator.CalculateWordFontSize(word, wordFrequencies); fontSizes.Add(fontSize); var font = new Font(fontName, fontSize); @@ -116,44 +119,16 @@ private List CalculateAndPutRectangles(CircularCloudLayouter layouter, IEnu return fontSizes; } - /// - /// Расчитывает размер шрифта для заданного слова на основе его частоты встречаемости. - /// - /// Строка, представляющая слово, для которого необходимо определить размер шрифта. - /// Словарь, содержащий частоту встречаемости каждого слова в тексте. - /// Размер шрифта для заданного слова. - - private const int BaseFontSize = 30; - private const int FontSizeMultiplier = 2; - private const int DefaultFontSize = 10; - private int CalculateWordFontSize(string word, Dictionary wordFrequencies) - { - if (wordFrequencies.TryGetValue(word, out var frequency)) - { - return Math.Max(BaseFontSize, BaseFontSize + frequency * FontSizeMultiplier); - } - return DefaultFontSize; - } - - - private Dictionary CalculateWordFrequencies(IEnumerable words) + public static Point CalculateCenter(int width, int height) { - var wordFrequencies = new Dictionary(); - - foreach (var word in words) - { - wordFrequencies.TryGetValue(word, out var frequency); - wordFrequencies[word] = frequency + 1; - } - - return wordFrequencies; - } + return new Point(width / Half, height / Half); + } private CircularCloudLayouter CreateLayouter(double angleStep = DefaultAngleStep, double radiusStep = DefaultRadiusStep) { - var center = new Point(_imageSettings.ImageWidth / 2, _imageSettings.ImageHeight / 2); + var center = CalculateCenter(_imageSettings.Width, _imageSettings.Height); var spiral = new Spiral(center, angleStep, radiusStep); return new CircularCloudLayouter(center, spiral); - } + } } } diff --git a/TagsCloudContainer/TagsCloud/TagCloudGenerator.cs b/TagsCloudContainer/TagsCloud/TagCloudGenerator.cs index 68946c7cc..99ae1933c 100644 --- a/TagsCloudContainer/TagsCloud/TagCloudGenerator.cs +++ b/TagsCloudContainer/TagsCloud/TagCloudGenerator.cs @@ -7,7 +7,7 @@ public class TagCloudGenerator : ITagCloudGenerator { public Bitmap GenerateTagCloud(IEnumerable words, IImageSettings imageSettings) { - var tagCloudImage = new Bitmap(imageSettings.ImageWidth, imageSettings.ImageHeight); + var tagCloudImage = new Bitmap(imageSettings.Width, imageSettings.Height); using (var graphics = Graphics.FromImage(tagCloudImage)) { graphics.Clear(imageSettings.BackgroundColor); From 2320a14cd8f2a3adc6cc7d411356fe0c8a110c9d Mon Sep 17 00:00:00 2001 From: sibogatovr Date: Fri, 2 Feb 2024 10:12:00 +0500 Subject: [PATCH 10/13] refactor: Improve variable names, code readability --- .../Interfaces/ICircularCloudLayouter.cs | 4 +- TagsCloudContainer/Interfaces/IFileReader.cs | 4 +- .../Interfaces/IImageSettings.cs | 5 ++- TagsCloudContainer/Program.cs | 6 +-- TagsCloudContainer/Readers/DocReader.cs | 10 +++-- TagsCloudContainer/Readers/DocxReader.cs | 9 ++-- TagsCloudContainer/Readers/FileReader.cs | 45 +++++++++++++------ TagsCloudContainer/Readers/TxtReader.cs | 8 ++-- .../TagsCloud/CircularCloudLayouter.cs | 26 +++++------ TagsCloudContainer/TagsCloud/ImageSettings.cs | 4 +- TagsCloudContainer/TagsCloud/TagCloudApp.cs | 24 ++++++---- .../Utility/CommandLineOptions.cs | 2 - TagsCloudContainer/Utility/Result.cs | 26 +++++++++++ .../CommandLineOptionsTests.cs | 2 - fp.sln | 31 +++++++++++++ 15 files changed, 145 insertions(+), 61 deletions(-) create mode 100644 TagsCloudContainer/Utility/Result.cs create mode 100644 fp.sln diff --git a/TagsCloudContainer/Interfaces/ICircularCloudLayouter.cs b/TagsCloudContainer/Interfaces/ICircularCloudLayouter.cs index 84fdd7268..d365331bd 100644 --- a/TagsCloudContainer/Interfaces/ICircularCloudLayouter.cs +++ b/TagsCloudContainer/Interfaces/ICircularCloudLayouter.cs @@ -4,8 +4,8 @@ namespace TagsCloudContainer.Interfaces { public interface ICircularCloudLayouter { - public Point CloudCenter { get; } - public IList Rectangles { get; } + public Point CloudCenter { get; init; } + public IList Rectangles { get; init; } Rectangle PutNextRectangle(string word, Font font); } } diff --git a/TagsCloudContainer/Interfaces/IFileReader.cs b/TagsCloudContainer/Interfaces/IFileReader.cs index 2ac078cfd..c8b9193c4 100644 --- a/TagsCloudContainer/Interfaces/IFileReader.cs +++ b/TagsCloudContainer/Interfaces/IFileReader.cs @@ -1,8 +1,10 @@  +using TagsCloudContainer.Utility; + namespace TagsCloudContainer.Interfaces { public interface IFileReader { - IEnumerable ReadWords(string filePath); + Result> ReadWords(string filePath); } } diff --git a/TagsCloudContainer/Interfaces/IImageSettings.cs b/TagsCloudContainer/Interfaces/IImageSettings.cs index 7dd42a9ca..b9901f0b8 100644 --- a/TagsCloudContainer/Interfaces/IImageSettings.cs +++ b/TagsCloudContainer/Interfaces/IImageSettings.cs @@ -4,8 +4,8 @@ namespace TagsCloudContainer.Interfaces { public interface IImageSettings { - Color BackgroundColor { get; } - Color FontColor { get; } + Color BackgroundColor { get; init; } + Color FontColor { get; init; } Font GetFont(); int Width { get; set; } int Height { get; set; } @@ -13,3 +13,4 @@ public interface IImageSettings void UpdateImageSettings(int width, int height); } } + diff --git a/TagsCloudContainer/Program.cs b/TagsCloudContainer/Program.cs index d68b4a046..b0bef882e 100644 --- a/TagsCloudContainer/Program.cs +++ b/TagsCloudContainer/Program.cs @@ -10,14 +10,14 @@ public class Program static void Main(string[] args) { Parser.Default.ParseArguments(args) - .WithParsed(o => + .WithParsed(options => { using (var serviceProvider = Startup.ConfigureServices()) { var tagCloudApp = serviceProvider.GetRequiredService(); - tagCloudApp.Run(o); + tagCloudApp.Run(options); } }); - } + } } } diff --git a/TagsCloudContainer/Readers/DocReader.cs b/TagsCloudContainer/Readers/DocReader.cs index 733863ef2..6fcce323f 100644 --- a/TagsCloudContainer/Readers/DocReader.cs +++ b/TagsCloudContainer/Readers/DocReader.cs @@ -1,27 +1,29 @@ using Spire.Doc; using Spire.Doc.Documents; using TagsCloudContainer.Interfaces; +using TagsCloudContainer.Utility; namespace TagsCloudContainer.Readers { public class DocReader : IFileReader { - public IEnumerable ReadWords(string filePath) + public Result> ReadWords(string filePath) { try { var document = new Document(); document.LoadFromFile(filePath); - return document.Sections + var words = document.Sections .Cast
() .SelectMany(section => section.Paragraphs.Cast()) .SelectMany(paragraph => paragraph.Text.Split(' ', StringSplitOptions.RemoveEmptyEntries)); + + return Result>.Success(words); } catch (Exception ex) { - Console.WriteLine($"Error reading .doc file: {ex.Message}"); - return Enumerable.Empty(); + return Result>.Failure($"Error reading .doc file: {ex.Message}"); } } } diff --git a/TagsCloudContainer/Readers/DocxReader.cs b/TagsCloudContainer/Readers/DocxReader.cs index 0cf9ad4c8..18e9a6a70 100644 --- a/TagsCloudContainer/Readers/DocxReader.cs +++ b/TagsCloudContainer/Readers/DocxReader.cs @@ -1,11 +1,12 @@ using NPOI.XWPF.UserModel; using TagsCloudContainer.Interfaces; +using TagsCloudContainer.Utility; namespace TagsCloudContainer.Readers { public class DocxReader : IFileReader { - public IEnumerable ReadWords(string filePath) + public Result> ReadWords(string filePath) { var words = new List(); @@ -18,13 +19,13 @@ public IEnumerable ReadWords(string filePath) words.AddRange(paragraph.Text.Split(' ', StringSplitOptions.RemoveEmptyEntries)); } } + + return Result>.Success(words); } catch (Exception ex) { - Console.WriteLine($"Error reading .docx file: {ex.Message}"); + return Result>.Failure($"Error reading .docx file: {ex.Message}"); } - - return words; } } } diff --git a/TagsCloudContainer/Readers/FileReader.cs b/TagsCloudContainer/Readers/FileReader.cs index d01752a91..215cc11be 100644 --- a/TagsCloudContainer/Readers/FileReader.cs +++ b/TagsCloudContainer/Readers/FileReader.cs @@ -2,31 +2,48 @@ using TagsCloudContainer.Enums; using TagsCloudContainer.Interfaces; using TagsCloudContainer.Readers; +using TagsCloudContainer.Utility; namespace TagsCloudContainer.TagsCloud { public class FileReader { - public IEnumerable ReadFile(string filePath) + public Result> ReadFile(string filePath) { - var fileReader = GetFileReader(filePath); - return fileReader.ReadWords(filePath); + var fileReaderResult = GetFileReader(filePath); + + if (fileReaderResult.IsSuccess) + { + var fileReader = fileReaderResult.Value; + return fileReader.ReadWords(filePath); + } + else + { + return Result>.Failure(fileReaderResult.ErrorMessage); + } } - private IFileReader GetFileReader(string filePath) + private Result GetFileReader(string filePath) { - FileType fileType = GetFileType(filePath); + try + { + FileType fileType = GetFileType(filePath); - switch (fileType) + switch (fileType) + { + case FileType.Doc: + return Result.Success(new DocReader()); + case FileType.Docx: + return Result.Success(new DocxReader()); + case FileType.Txt: + return Result.Success(new TxtReader()); + default: + return Result.Failure("Unsupported file extension"); + } + } + catch (Exception ex) { - case FileType.Doc: - return new DocReader(); - case FileType.Docx: - return new DocxReader(); - case FileType.Txt: - return new TxtReader(); - default: - throw new InvalidOperationException("Unsupported file extension"); + return Result.Failure($"Error getting file reader: {ex.Message}"); } } diff --git a/TagsCloudContainer/Readers/TxtReader.cs b/TagsCloudContainer/Readers/TxtReader.cs index d0c75f157..18f23da6b 100644 --- a/TagsCloudContainer/Readers/TxtReader.cs +++ b/TagsCloudContainer/Readers/TxtReader.cs @@ -1,10 +1,11 @@ using TagsCloudContainer.Interfaces; +using TagsCloudContainer.Utility; namespace TagsCloudContainer.Readers { public class TxtReader : IFileReader { - public IEnumerable ReadWords(string filePath) + public Result> ReadWords(string filePath) { try { @@ -14,12 +15,11 @@ public IEnumerable ReadWords(string filePath) var nonEmptyWords = words.Where(word => !string.IsNullOrEmpty(word)); - return nonEmptyWords; + return Result>.Success(nonEmptyWords); } catch (Exception ex) { - Console.WriteLine($"Error reading file: {ex.Message}"); - return Enumerable.Empty(); + return Result>.Failure($"Error reading file: {ex.Message}"); } } } diff --git a/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs b/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs index f75b40300..dabd370c0 100644 --- a/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs +++ b/TagsCloudContainer/TagsCloud/CircularCloudLayouter.cs @@ -1,24 +1,22 @@ using System.Drawing; using TagsCloudContainer.Interfaces; +using TagsCloudContainer.Utility; namespace TagsCloudContainer.TagsCloud { public class CircularCloudLayouter : ICircularCloudLayouter { - private readonly Point center; - private readonly List rectangles; private readonly INextPointProvider pointProvider; + public Point CloudCenter { get; init; } = Point.Empty; + public IList Rectangles { get; init; } = new List(); + public CircularCloudLayouter(Point center, INextPointProvider pointProvider) { - this.center = center; - rectangles = new(); + CloudCenter = center; this.pointProvider = pointProvider; } - public Point CloudCenter => center; - public IList Rectangles => rectangles; - private const int MinPositiveValue = 1; private const int MinWidth = 0; private const int MinHeight = 0; @@ -28,7 +26,7 @@ public Rectangle PutNextRectangle(Size rectangleSize) ValidateRectangleSize(rectangleSize); var currentRectangle = CreateNewRectangle(rectangleSize); - rectangles.Add(currentRectangle); + Rectangles.Add(currentRectangle); return currentRectangle; } @@ -38,7 +36,7 @@ public Rectangle PutNextRectangle(string word, Font font) var textSize = MeasureTextSize(word, font); return PutNextRectangle(textSize); } - + private Size MeasureTextSize(string text, Font font) { // размер минимального временного изображения для измерения текста @@ -56,12 +54,14 @@ private Size MeasureTextSize(string text, Font font) } } - private void ValidateRectangleSize(Size rectangleSize) + private Result ValidateRectangleSize(Size rectangleSize) { if (rectangleSize.Width <= MinWidth || rectangleSize.Height <= MinHeight) { - throw new ArgumentException("Width and height of the rectangle must be greater than zero"); + return Result.Failure("Width and height of the rectangle must be greater than zero"); } + + return Result.Success(rectangleSize); } private Rectangle CreateNewRectangle(Size rectangleSize) @@ -87,8 +87,8 @@ private Point GetUpperLeftCorner(Point rectangleCenter, Size rectangleSize) private bool RectanglesIntersect(Rectangle newRectangle) { - return rectangles.Any(rect => rect.IntersectsWith(newRectangle)); + return Rectangles.Any(rect => rect.IntersectsWith(newRectangle)); } - + } } diff --git a/TagsCloudContainer/TagsCloud/ImageSettings.cs b/TagsCloudContainer/TagsCloud/ImageSettings.cs index 7c4aca608..507a72cc3 100644 --- a/TagsCloudContainer/TagsCloud/ImageSettings.cs +++ b/TagsCloudContainer/TagsCloud/ImageSettings.cs @@ -5,8 +5,8 @@ namespace TagsCloudContainer.TagsCloud { public class ImageSettings : IImageSettings { - public Color BackgroundColor { get; } = Color.White; - public Color FontColor { get; } = Color.Black; + public Color BackgroundColor { get; init; } = Color.White; + public Color FontColor { get; init; } = Color.Black; public int Width { get; set; } = 1600; public int Height { get; set; } = 1200; diff --git a/TagsCloudContainer/TagsCloud/TagCloudApp.cs b/TagsCloudContainer/TagsCloud/TagCloudApp.cs index 6b970f0be..cc4e054d4 100644 --- a/TagsCloudContainer/TagsCloud/TagCloudApp.cs +++ b/TagsCloudContainer/TagsCloud/TagCloudApp.cs @@ -35,15 +35,23 @@ public void Run(CommandLineOptions options) { SetFontAndImageSettings(options.FontName, options.ImageWidth, options.ImageHeight); - var words = _fileReader.ReadFile(options.TextFilePath); - var processedWords = _preprocessor.Process(words, options.BoringWordsFilePath); - var uniqueWordCount = CountUniqueWords(processedWords); + var wordsResult = _fileReader.ReadFile(options.TextFilePath); - var (fontColor, highlightColor) = GetColors(options.FontColor, options.HighlightColor); + if (wordsResult.IsSuccess) + { + var processedWords = _preprocessor.Process(wordsResult.Value, options.BoringWordsFilePath); + var uniqueWordCount = CountUniqueWords(processedWords); + + var (fontColor, highlightColor) = GetColors(options.FontColor, options.HighlightColor); - var tagCloudImage = GenerateTagCloud(processedWords, options.FontName, fontColor, highlightColor, options.PercentageToHighLight); + var tagCloudImage = GenerateTagCloud(processedWords, options.FontName, fontColor, highlightColor, options.PercentageToHighLight); - SaveTagCloudImage(tagCloudImage, outputDirectory, uniqueWordCount); + SaveTagCloudImage(tagCloudImage, outputDirectory, uniqueWordCount); + } + else + { + Console.WriteLine($"Error reading file: {wordsResult.ErrorMessage}"); + } } private (Color fontColor, Color highlightColor) GetColors(string fontColorName, string highlightColorName) @@ -122,13 +130,13 @@ private List CalculateAndPutRectangles(CircularCloudLayouter layouter, IEnu public static Point CalculateCenter(int width, int height) { return new Point(width / Half, height / Half); - } + } private CircularCloudLayouter CreateLayouter(double angleStep = DefaultAngleStep, double radiusStep = DefaultRadiusStep) { var center = CalculateCenter(_imageSettings.Width, _imageSettings.Height); var spiral = new Spiral(center, angleStep, radiusStep); return new CircularCloudLayouter(center, spiral); - } + } } } diff --git a/TagsCloudContainer/Utility/CommandLineOptions.cs b/TagsCloudContainer/Utility/CommandLineOptions.cs index 26f619fc5..17278e5e0 100644 --- a/TagsCloudContainer/Utility/CommandLineOptions.cs +++ b/TagsCloudContainer/Utility/CommandLineOptions.cs @@ -31,7 +31,5 @@ public class CommandLineOptions [Option('p', "percentageToHighlight", Required = false, Default=0.2, HelpText = "Percentage To Highlight popular words")] public double PercentageToHighLight { get; set; } - - } } diff --git a/TagsCloudContainer/Utility/Result.cs b/TagsCloudContainer/Utility/Result.cs new file mode 100644 index 000000000..28047f6dd --- /dev/null +++ b/TagsCloudContainer/Utility/Result.cs @@ -0,0 +1,26 @@ +namespace TagsCloudContainer.Utility +{ + public struct Result + { + public bool IsSuccess { get; } + public T Value { get; } + public string ErrorMessage { get; } + + private Result(T value) + { + IsSuccess = true; + Value = value; + ErrorMessage = null; + } + + private Result(string errorMessage) + { + IsSuccess = false; + Value = default; + ErrorMessage = errorMessage; + } + + public static Result Success(T value) => new Result(value); + public static Result Failure(string errorMessage) => new Result(errorMessage); + } +} diff --git a/TagsCloudContainerTests/CommandLineOptionsTests.cs b/TagsCloudContainerTests/CommandLineOptionsTests.cs index 5ae781df9..5a21015fb 100644 --- a/TagsCloudContainerTests/CommandLineOptionsTests.cs +++ b/TagsCloudContainerTests/CommandLineOptionsTests.cs @@ -42,7 +42,5 @@ public void ParsingWithoutArguments_ShouldUseDefaultValues() Assert.That(options.TextFilePath, Is.EqualTo("src/text.txt")); Assert.That(options.FontColor, Is.EqualTo("Green")); } - - } } diff --git a/fp.sln b/fp.sln new file mode 100644 index 000000000..f678e4d63 --- /dev/null +++ b/fp.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34330.188 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TagsCloudContainer", "TagsCloudContainer\TagsCloudContainer.csproj", "{B6AFBD5A-A82F-4668-9C7F-881512BB9EDF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TagsCloudContainerTests", "TagsCloudContainerTests\TagsCloudContainerTests.csproj", "{05D64DA4-A1B9-401F-AD25-6D4AEBEE68B5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B6AFBD5A-A82F-4668-9C7F-881512BB9EDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6AFBD5A-A82F-4668-9C7F-881512BB9EDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6AFBD5A-A82F-4668-9C7F-881512BB9EDF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6AFBD5A-A82F-4668-9C7F-881512BB9EDF}.Release|Any CPU.Build.0 = Release|Any CPU + {05D64DA4-A1B9-401F-AD25-6D4AEBEE68B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {05D64DA4-A1B9-401F-AD25-6D4AEBEE68B5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {05D64DA4-A1B9-401F-AD25-6D4AEBEE68B5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {05D64DA4-A1B9-401F-AD25-6D4AEBEE68B5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4994D982-F2FE-4BC8-820A-6E567F12810C} + EndGlobalSection +EndGlobal From 21aa80d20d276b6ecc4803b0107083013e936e3d Mon Sep 17 00:00:00 2001 From: sibogatovr Date: Tue, 6 Feb 2024 03:32:30 +0500 Subject: [PATCH 11/13] feat: Add Readme.md file --- TagsCloudContainer/Readme.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 TagsCloudContainer/Readme.md diff --git a/TagsCloudContainer/Readme.md b/TagsCloudContainer/Readme.md new file mode 100644 index 000000000..3e06303aa --- /dev/null +++ b/TagsCloudContainer/Readme.md @@ -0,0 +1,18 @@ +# TagsCloudContainer + + . , , . + +## : + +- . +- . +- . +- , , . +- CLI. +- : \*.doc, \*.docx, \*.txt. +- . +- . + +## + +- , 'boring_words.txt' \ No newline at end of file From 553a05336ff3caec8fce67c85cf5eafcc112d4d7 Mon Sep 17 00:00:00 2001 From: sibogatovr Date: Tue, 6 Feb 2024 03:36:33 +0500 Subject: [PATCH 12/13] refactor: decomposition Run method, update the FileReader --- TagsCloudContainer/Enums/FileType.cs | 7 ++++- .../Interfaces/IImageSettings.cs | 2 +- TagsCloudContainer/Readers/FileReader.cs | 31 ++++++++++++------- TagsCloudContainer/TagsCloud/ImageSettings.cs | 2 +- TagsCloudContainer/TagsCloud/TagCloudApp.cs | 22 +++++++------ 5 files changed, 41 insertions(+), 23 deletions(-) diff --git a/TagsCloudContainer/Enums/FileType.cs b/TagsCloudContainer/Enums/FileType.cs index 9f38271cf..3158a7f08 100644 --- a/TagsCloudContainer/Enums/FileType.cs +++ b/TagsCloudContainer/Enums/FileType.cs @@ -1,9 +1,14 @@ -namespace TagsCloudContainer.Enums +using System.ComponentModel; + +namespace TagsCloudContainer.Enums { public enum FileType { + [Description(".doc")] Doc, + [Description(".docx")] Docx, + [Description(".txt")] Txt } } diff --git a/TagsCloudContainer/Interfaces/IImageSettings.cs b/TagsCloudContainer/Interfaces/IImageSettings.cs index b9901f0b8..3b48250aa 100644 --- a/TagsCloudContainer/Interfaces/IImageSettings.cs +++ b/TagsCloudContainer/Interfaces/IImageSettings.cs @@ -10,7 +10,7 @@ public interface IImageSettings int Width { get; set; } int Height { get; set; } - void UpdateImageSettings(int width, int height); + void UpdateSettings(int width, int height); } } diff --git a/TagsCloudContainer/Readers/FileReader.cs b/TagsCloudContainer/Readers/FileReader.cs index 215cc11be..693d85479 100644 --- a/TagsCloudContainer/Readers/FileReader.cs +++ b/TagsCloudContainer/Readers/FileReader.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.ComponentModel; using TagsCloudContainer.Enums; using TagsCloudContainer.Interfaces; using TagsCloudContainer.Readers; @@ -47,21 +47,30 @@ private Result GetFileReader(string filePath) } } - private FileType GetFileType(string filePath) + static FileType GetFileType(string filePath) { string fileExtension = Path.GetExtension(filePath)?.ToLower(); - switch (fileExtension) + var fileTypes = Enum.GetValues(typeof(FileType)).Cast(); + + foreach (var fileType in fileTypes) { - case ".doc": - return FileType.Doc; - case ".docx": - return FileType.Docx; - case ".txt": - return FileType.Txt; - default: - throw new InvalidOperationException("Unsupported file extension"); + var descriptionAttribute = GetEnumDescription(fileType); + if (descriptionAttribute != null && descriptionAttribute.Equals(fileExtension)) + { + return fileType; + } } + + throw new InvalidOperationException("Unsupported file extension"); + } + + static string GetEnumDescription(Enum value) + { + var field = value.GetType().GetField(value.ToString()); + var attribute = (DescriptionAttribute)Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)); + + return attribute?.Description; } } } diff --git a/TagsCloudContainer/TagsCloud/ImageSettings.cs b/TagsCloudContainer/TagsCloud/ImageSettings.cs index 507a72cc3..27f31a4ac 100644 --- a/TagsCloudContainer/TagsCloud/ImageSettings.cs +++ b/TagsCloudContainer/TagsCloud/ImageSettings.cs @@ -15,7 +15,7 @@ public Font GetFont() return new Font("Verdana", 20); } - public void UpdateImageSettings(int width, int height) + public void UpdateSettings(int width, int height) { Width = width; Height = height; diff --git a/TagsCloudContainer/TagsCloud/TagCloudApp.cs b/TagsCloudContainer/TagsCloud/TagCloudApp.cs index cc4e054d4..9159871a1 100644 --- a/TagsCloudContainer/TagsCloud/TagCloudApp.cs +++ b/TagsCloudContainer/TagsCloud/TagCloudApp.cs @@ -39,14 +39,7 @@ public void Run(CommandLineOptions options) if (wordsResult.IsSuccess) { - var processedWords = _preprocessor.Process(wordsResult.Value, options.BoringWordsFilePath); - var uniqueWordCount = CountUniqueWords(processedWords); - - var (fontColor, highlightColor) = GetColors(options.FontColor, options.HighlightColor); - - var tagCloudImage = GenerateTagCloud(processedWords, options.FontName, fontColor, highlightColor, options.PercentageToHighLight); - - SaveTagCloudImage(tagCloudImage, outputDirectory, uniqueWordCount); + ProcessAndGenerateTagCloud(wordsResult.Value, options); } else { @@ -54,6 +47,17 @@ public void Run(CommandLineOptions options) } } + private void ProcessAndGenerateTagCloud(IEnumerable words, CommandLineOptions options) + { + var processedWords = _preprocessor.Process(words, options.BoringWordsFilePath); + var uniqueWordCount = CountUniqueWords(processedWords); + var (fontColor, highlightColor) = GetColors(options.FontColor, options.HighlightColor); + + var tagCloudImage = GenerateTagCloud(processedWords, options.FontName, fontColor, highlightColor, options.PercentageToHighLight); + + SaveTagCloudImage(tagCloudImage, outputDirectory, uniqueWordCount); + } + private (Color fontColor, Color highlightColor) GetColors(string fontColorName, string highlightColorName) { return (Color.FromName(fontColorName), Color.FromName(highlightColorName)); @@ -62,7 +66,7 @@ public void Run(CommandLineOptions options) private void SetFontAndImageSettings(string fontName, int imageWidth, int imageHeight) { SetFontName(fontName); - _imageSettings.UpdateImageSettings(imageWidth, imageHeight); + _imageSettings.UpdateSettings(imageWidth, imageHeight); } public void SaveTagCloudImage(Bitmap tagCloudImage, string outputDirectory, int uniqueWordCount) From ed0c9b1558b79108bbca877f7c7db6edc043d203 Mon Sep 17 00:00:00 2001 From: sibogatovr Date: Tue, 6 Feb 2024 21:34:50 +0500 Subject: [PATCH 13/13] fix: encoding issue in Readme.md --- TagsCloudContainer/Readme.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/TagsCloudContainer/Readme.md b/TagsCloudContainer/Readme.md index 3e06303aa..83bce5bad 100644 --- a/TagsCloudContainer/Readme.md +++ b/TagsCloudContainer/Readme.md @@ -1,18 +1,18 @@ # TagsCloudContainer - . , , . +Проект представляет собой программу для генерации облака тегов из файла с набором слов. Программа осуществляет удаление скучных слов, перечень которых указан в отдельном файле, а также приведение всех слов к нижнему регистру для унификации. -## : +## Внесенные изменения: -- . -- . -- . -- , , . -- CLI. -- : \*.doc, \*.docx, \*.txt. -- . -- . +- Добавлена функциональность удаления скучных слов. +- Реализовано приведение всех слов к нижнему регистру. +- Реализовано изменение цвета ТОП слов. +- Реализована возможность изменить шрифт, цвет, размер. +- Добавлен CLI. +- Реализованы ридеры: \*.doc, \*.docx, \*.txt. +- Добавлены соответствующие тесты для новой функциональности. +- Внесены мелкие улучшения и исправления. -## +## Исключение слов из облака -- , 'boring_words.txt' \ No newline at end of file +- Список слов которые надо исключить, находятся в файле 'boring_words.txt' \ No newline at end of file