diff --git a/TagsCloudContainer/TagsCloudApp/CloudVisualizer.cs b/TagsCloudContainer/TagsCloudApp/CloudVisualizer.cs new file mode 100644 index 000000000..b3cfe0835 --- /dev/null +++ b/TagsCloudContainer/TagsCloudApp/CloudVisualizer.cs @@ -0,0 +1,51 @@ +using System.Drawing; +using System.Drawing.Imaging; +using TagsCloudContainer; + +namespace TagsCloudApp; + +public class CloudVisualizer +{ + private static Bitmap _bitmap; + public static Graphics Graphics { get; private set; } + + public static void PrepareGraphics(Size imageSize) + { + _bitmap = new Bitmap(imageSize.Width, imageSize.Height); + Graphics = Graphics.FromImage(_bitmap); + } + + public static void Draw(TextRectangleContainerProcessor processor, + ImageGeneratorInfo info, + string inputFile, + IWordMeasurer wordMeasurer) + { + var path = info.OutputFileName; + var dir = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) + Directory.CreateDirectory(dir); + + Graphics.Clear(info.BackgroundColor); + + using var brush = new SolidBrush(info.TextColor); + + var format = new StringFormat + { + Alignment = StringAlignment.Center, + LineAlignment = StringAlignment.Center + }; + + foreach (var container in processor.ProcessFile(inputFile, wordMeasurer)) + { + if (container is null) + continue; + var rect = container.Rectangle; + using var font = + new Font(info.Font.FontFamily, info.Font.Size * container.FontSizeScale, info.Font.Style); + Graphics.DrawString(container.Text, font, brush, rect, format); + } + + _bitmap.Save(path); + } + +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudApp/ConsoleClient.cs b/TagsCloudContainer/TagsCloudApp/ConsoleClient.cs new file mode 100644 index 000000000..36739594d --- /dev/null +++ b/TagsCloudContainer/TagsCloudApp/ConsoleClient.cs @@ -0,0 +1,129 @@ +using System.Drawing; +using ErrorHandling; +using TagsCloudContainer; + +namespace TagsCloudApp; + +public class ConsoleClient : IClient +{ + private const string ReadFontColorPrompt = "Введите английское название цвета шрифта (enter для дефолтного значения):"; + private const string ReadBGColorPrompt = "Введите английское название цвета фона (enter для дефолтного значения):"; + private const string ReadFontNamePrompt = "Введите название шрифта (enter для дефолтного значения):"; + private const string ReadFontSizePrompt = "Введите размер изображения через пробел двумя числами (enter для дефолтного значения):"; + private const string ReadOutputFileNamePrompt = "Введите желаемое имя для выходного файла (enter для дефолтного значения):"; + private const string ReadBanWordsPrompt = "Введите через запятую слова, которые хотите игнорировать (enter, если хотите видеть все слова)"; + private const string ReadOutputFileFormat = "Введите желаемый формат выходного файла (enter для дефолтного значения)"; + + public ImageGeneratorInfo GetImageGeneratorInfo() + { + var textColor = ReadColor(ReadFontColorPrompt).GetValueOrThrow(); + var bgColor = ReadColor(ReadBGColorPrompt).GetValueOrThrow(); + var font = ReadFont(ReadFontNamePrompt).GetValueOrThrow(); + var imageSize = ReadSize(ReadFontSizePrompt).GetValueOrThrow(); + var outputFile = ReadString(ReadOutputFileNamePrompt); + var banWords = ReadList(ReadBanWordsPrompt); + var outputFileFormat = ReadFormat(ReadOutputFileFormat).GetValueOrThrow(); + + return new ImageGeneratorInfo( + textColor, + bgColor, + font, + imageSize, + outputFile, + banWords, + outputFileFormat + ); + } + + private Result ReadColor(string prompt) + { + Console.WriteLine(prompt); + var input = Console.ReadLine(); + if (string.IsNullOrEmpty(input)) + return Result.Ok(null); + var color = Color.FromName(input); + if (color.IsKnownColor) + return Result.Ok(color); + return Result.Fail($"Цвета {color} нет, попробуй ещё раз"); + } + + private Result ReadFont(string prompt, float defaultSize = 60) + { + Console.WriteLine(prompt); + var input = Console.ReadLine(); + if (string.IsNullOrEmpty(input)) + return Result.Ok(null); + if (FontFamily.Families.Any(f => f.Name.Equals(input, StringComparison.OrdinalIgnoreCase))) + return Result.Ok(new Font(input, defaultSize)); + return Result.Fail($"Шрифта {input} нет, попробуй ещё раз"); + } + + private Result ReadSize(string prompt) + { + Console.WriteLine(prompt); + var input = Console.ReadLine(); + if (string.IsNullOrEmpty(input)) + return Result.Ok(null); + var parts = input.Split(' ', StringSplitOptions.RemoveEmptyEntries); + if (parts.Length == 2 && + int.TryParse(parts[0], out var width) && + int.TryParse(parts[1], out var height)) + { + return Result.Ok(new Size(width, height)); + } + return Result.Fail("Нужно ввести два числа через пробел"); + } + + private string? ReadString(string prompt) + { + Console.WriteLine(prompt); + var input = Console.ReadLine(); + return string.IsNullOrEmpty(input) ? null : input; + } + + private List? ReadList(string prompt) + { + Console.WriteLine(prompt); + var input = Console.ReadLine(); + return string.IsNullOrEmpty(input) ? new List() : input.Split(',').Select(s => s.Trim()).ToList(); + } + + private Result ReadFormat(string prompt) + { + Console.WriteLine(prompt); + var input = Console.ReadLine(); + if (string.IsNullOrEmpty(input)) + return Result.Ok(null); + if (input[0] == '.') + input = input[1..]; + switch (input) + { + case "png": + break; + case "jpg": + break; + case "jpeg": + break; + case "bmp": + break; + default: + return Result.Fail( + $"Формат {input} не поддерживается, повторите попытку! (Доступные форматы: png, jpg, jpeg, bmp"); + } + return Result.Ok(input); + } + + public Result GetImagePath() + { + Console.WriteLine("Введи название входного файла:"); + var fileName = Console.ReadLine(); + if (string.IsNullOrEmpty(fileName)) + return Result.Fail("Имя файла не может быть пустым!"); + if (!File.Exists(fileName)) + { + var fullPath = Path.GetFullPath(fileName); + return Result.Fail($"Файл {fileName} не найден по пути {fullPath}, повтори ввод"); + } + return Result.Ok(fileName); + } +} diff --git a/TagsCloudContainer/TagsCloudApp/IClient.cs b/TagsCloudContainer/TagsCloudApp/IClient.cs new file mode 100644 index 000000000..fe01c3b73 --- /dev/null +++ b/TagsCloudContainer/TagsCloudApp/IClient.cs @@ -0,0 +1,11 @@ +using ErrorHandling; +using TagsCloudContainer; + +namespace TagsCloudApp; + +public interface IClient +{ + public ImageGeneratorInfo GetImageGeneratorInfo(); + + public Result GetImagePath(); +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudApp/Program.cs b/TagsCloudContainer/TagsCloudApp/Program.cs new file mode 100644 index 000000000..2f2a73e30 --- /dev/null +++ b/TagsCloudContainer/TagsCloudApp/Program.cs @@ -0,0 +1,27 @@ +using System.Drawing; +using Autofac; +using TagsCloudApp; +using TagsCloudContainer; + +public static class Program +{ + public static void Main() + { + var client = new ConsoleClient(); + var imageGeneratorInfo = client.GetImageGeneratorInfo(); + var fileName = client.GetImagePath().GetValueOrThrow(); + var imageSize = imageGeneratorInfo.ImageSize; + var imageCenter = new Point(imageSize.Width / 2, imageSize.Height / 2); + CloudVisualizer.PrepareGraphics(imageSize); + var container = ContainerComposer.Compose(imageCenter, imageGeneratorInfo.ImageSize, + CloudVisualizer.Graphics, imageGeneratorInfo.Font, imageGeneratorInfo.BanWords); + + var wordProcessor = container + .Resolve(); + + var measurer = container + .Resolve(); + + CloudVisualizer.Draw(wordProcessor, imageGeneratorInfo, fileName, measurer); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudApp/TagsCloudApp.csproj b/TagsCloudContainer/TagsCloudApp/TagsCloudApp.csproj new file mode 100644 index 000000000..9ef808fde --- /dev/null +++ b/TagsCloudContainer/TagsCloudApp/TagsCloudApp.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/TagsCloudContainer/TagsCloudContainer.sln b/TagsCloudContainer/TagsCloudContainer.sln new file mode 100644 index 000000000..dbd2051be --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagsCloudContainer", "TagsCloudContainer\TagsCloudContainer.csproj", "{B669CC7B-C5A0-40AE-AF5F-E2A98EBC343A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagsCloudApp", "TagsCloudApp\TagsCloudApp.csproj", "{39391998-1546-4A9D-B534-A4756C13A9DF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagsCloudVisualization", "TagsCloudVisualization\TagsCloudVisualization.csproj", "{305481A1-EF22-489A-8B87-338FDDEE48B5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B669CC7B-C5A0-40AE-AF5F-E2A98EBC343A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B669CC7B-C5A0-40AE-AF5F-E2A98EBC343A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B669CC7B-C5A0-40AE-AF5F-E2A98EBC343A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B669CC7B-C5A0-40AE-AF5F-E2A98EBC343A}.Release|Any CPU.Build.0 = Release|Any CPU + {39391998-1546-4A9D-B534-A4756C13A9DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39391998-1546-4A9D-B534-A4756C13A9DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39391998-1546-4A9D-B534-A4756C13A9DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39391998-1546-4A9D-B534-A4756C13A9DF}.Release|Any CPU.Build.0 = Release|Any CPU + {305481A1-EF22-489A-8B87-338FDDEE48B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {305481A1-EF22-489A-8B87-338FDDEE48B5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {305481A1-EF22-489A-8B87-338FDDEE48B5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {305481A1-EF22-489A-8B87-338FDDEE48B5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/TagsCloudContainer/TagsCloudContainer/BoringWordsProcessor.cs b/TagsCloudContainer/TagsCloudContainer/BoringWordsProcessor.cs new file mode 100644 index 000000000..be0ee207a --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/BoringWordsProcessor.cs @@ -0,0 +1,35 @@ +using WeCantSpell.Hunspell; + +namespace TagsCloudContainer; + +public class BoringWordsProcessor : IBoringWordsProcessor +{ + private const float BoringWordQuantityThreshold = 0.35f; + private readonly List _banWords; + + public BoringWordsProcessor(List banWords) + { + this._banWords = banWords; + } + + public Dictionary WordsToLowerAndRemoveBoringWords(List words) + { + var banWordsDict = WordList.CreateFromWords(_banWords); + var frequencyDict = new Dictionary(); + foreach (var word in words) + { + var lowerCaseWord = word.ToLower(); + if (banWordsDict.Check(lowerCaseWord)) + continue; + frequencyDict.TryAdd(lowerCaseWord, 0); + ++frequencyDict[lowerCaseWord]; + var a = (float)frequencyDict[lowerCaseWord] / words.Count; + } + + return frequencyDict + .OrderByDescending(x => x.Value) + .ThenBy(x => x.Key) + .Where(x => ((float)x.Value / words.Count) < BoringWordQuantityThreshold) + .ToDictionary(x => x.Key, x => x.Value); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer/CalculateNextRectangleSize.cs b/TagsCloudContainer/TagsCloudContainer/CalculateNextRectangleSize.cs new file mode 100644 index 000000000..a70caf265 --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/CalculateNextRectangleSize.cs @@ -0,0 +1,42 @@ +using System.Drawing; + +namespace TagsCloudContainer; + +public class RectangleSizeCalculator +{ + private Size _maxSize; + private Size _minSize; + private int _maxFrequency; + private bool _isMaxFrequencyInitialized; + + internal RectangleSizeCalculator(Size imageSize) + { + _maxSize = new Size((int)(imageSize.Width), (int)(imageSize.Height * 0.1)); + _minSize = new Size((int)(imageSize.Width * 0.01), (int)(imageSize.Height * 0.005)); + } + + internal Size CalculateNextRectangleSize(KeyValuePair wordInfo, + IWordMeasurer wordMeasurer, out float scale) + { + var wordFrequency = wordInfo.Value; + if (!_isMaxFrequencyInitialized) + { + _isMaxFrequencyInitialized = true; + _maxFrequency = wordFrequency; + } + + scale = (float)wordFrequency / _maxFrequency; + if (scale < 0.05) + return Size.Empty; + var rawSize = wordMeasurer.Measure(wordInfo.Key, scale); + return ClampSize(rawSize); + } + + private Size ClampSize(Size size) + { + size.Width = Math.Clamp(size.Width, _minSize.Width, _maxSize.Width); + size.Height = Math.Clamp(size.Height, _minSize.Height, _maxSize.Height); + + return Size.Round(size); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer/ContainerComposer.cs b/TagsCloudContainer/TagsCloudContainer/ContainerComposer.cs new file mode 100644 index 000000000..c7430e2e1 --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/ContainerComposer.cs @@ -0,0 +1,20 @@ +using System.Drawing; +using Autofac; +using TagsCloudVisualization; + +namespace TagsCloudContainer; + +public static class ContainerComposer +{ + public static IContainer Compose(Point center, Size imageSize, Graphics graphics, Font font, List banWords) + { + var builder = new ContainerBuilder(); + builder.RegisterInstance(new CircularCloudLayouter(center, imageSize)).As(); + builder.RegisterInstance(new TxtReader()).As(); + builder.RegisterInstance(new RectangleSizeCalculator(imageSize)); + builder.RegisterInstance(new BoringWordsProcessor(banWords)).As(); + builder.RegisterType(); + builder.RegisterInstance(new WordMeasurer(graphics, font)).As(); + return builder.Build(); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer/IBoringWordsProcessor.cs b/TagsCloudContainer/TagsCloudContainer/IBoringWordsProcessor.cs new file mode 100644 index 000000000..a553f5caa --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/IBoringWordsProcessor.cs @@ -0,0 +1,6 @@ +namespace TagsCloudContainer; + +public interface IBoringWordsProcessor +{ + public Dictionary WordsToLowerAndRemoveBoringWords(List words); +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer/IFileReader.cs b/TagsCloudContainer/TagsCloudContainer/IFileReader.cs new file mode 100644 index 000000000..dc76caa31 --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/IFileReader.cs @@ -0,0 +1,6 @@ +namespace TagsCloudContainer; + +public interface IFileReader +{ + internal List ReadFile(string path); +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer/IWordMeasurer.cs b/TagsCloudContainer/TagsCloudContainer/IWordMeasurer.cs new file mode 100644 index 000000000..40b1d4358 --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/IWordMeasurer.cs @@ -0,0 +1,9 @@ +using System.Drawing; + +namespace TagsCloudContainer; + +public interface IWordMeasurer +{ + public Size Measure(string word, float scale); + public Font GetFont(float scale); +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer/ImageGeneratorInfo.cs b/TagsCloudContainer/TagsCloudContainer/ImageGeneratorInfo.cs new file mode 100644 index 000000000..7566a89b4 --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/ImageGeneratorInfo.cs @@ -0,0 +1,28 @@ +using System.Drawing; + +namespace TagsCloudContainer; + +public class ImageGeneratorInfo +{ + public Color TextColor { get; set; } + public Color BackgroundColor { get; set; } + public Font Font { get; set; } + public Size ImageSize { get; set; } + public string OutputFileName { get; set; } + public List BanWords { get; set; } + + public ImageGeneratorInfo(Color? textColor = null, Color? backgroundColor = null, + Font? font = null, Size? imageSize = null, string? outputFileName = null, List? banWords = null, + string? outputFileFormat = null) + { + Font = font ?? new Font(FontFamily.GenericSansSerif, 60); + TextColor = textColor ?? Color.Black; + BackgroundColor = backgroundColor ?? Color.White; + ImageSize = imageSize ?? new Size(1000, 1000); + OutputFileName = outputFileName ?? "output"; + if (OutputFileName[^1] != '.') + OutputFileName += "."; + OutputFileName += outputFileFormat ?? "bmp"; + BanWords = banWords ?? new List(); + } +} diff --git a/TagsCloudContainer/TagsCloudContainer/TagsCloudContainer.csproj b/TagsCloudContainer/TagsCloudContainer/TagsCloudContainer.csproj new file mode 100644 index 000000000..b9369e663 --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/TagsCloudContainer.csproj @@ -0,0 +1,25 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + + + + + + + diff --git a/TagsCloudContainer/TagsCloudContainer/Tests/BoringWordsProcessorTests.cs b/TagsCloudContainer/TagsCloudContainer/Tests/BoringWordsProcessorTests.cs new file mode 100644 index 000000000..7b5400a9d --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/Tests/BoringWordsProcessorTests.cs @@ -0,0 +1,90 @@ +using System.Drawing; +using NUnit.Framework; +using Autofac; +using FluentAssertions; + +namespace TagsCloudContainer.Tests; + +[TestFixture] +public class BoringWordsProcessorTests +{ + private Point _center; + private Size _imageSize; + private string _filePath = "TestData"; + private IContainer _container; + private Graphics _graphics; + private Bitmap _bitmap; + + [SetUp] + public void Setup() + { + _center = new Point(400, 400); + _imageSize = new Size(800, 800); + _bitmap = new Bitmap(_imageSize.Width, _imageSize.Height); + _graphics = Graphics.FromImage(_bitmap); + var font = new Font(FontFamily.GenericSansSerif, 20); + + _container = ContainerComposer.Compose(_center, _imageSize, _graphics, font,["банворд"]); + } + + [Test] + public void WordsToLowerAndRemoveBoringWords_HandleFile_Should_IgnoreBanWords() + { + var path = Path.Combine(_filePath, + "TXTReader_ReadFile_Should_IgnoreBanWords.txt"); + var expectedData = new[] { "слово" }; + + var inputData = _container + .Resolve() + .ReadFile(path); + + var resultData = _container + .Resolve() + .WordsToLowerAndRemoveBoringWords(inputData).Keys; + + resultData.Should().BeEquivalentTo(expectedData); + } + + [Test] + public void WordsToLowerAndRemoveBoringWords_HandleFile_Should_MakeWordsToLower() + { + var path = Path.Combine(_filePath, + "WordsToLowerAndRemoveBoringWords_HandleFile_Should_MakeWordsToLower.txt"); + var expectedData = new[] { "слово" }; + + var inputData = _container + .Resolve() + .ReadFile(path); + + var resultData = _container + .Resolve() + .WordsToLowerAndRemoveBoringWords(inputData).Keys; + + resultData.Should().BeEquivalentTo(expectedData); + } + + [Test] + public void WordsToLowerAndRemoveBoringWords_HandleFile_Should_IgnoreBoringWords() + { + var path = Path.Combine(_filePath, + "WordsToLowerAndRemoveBoringWords_HandleFile_Should_IgnoreBoringWords.txt"); + var expectedData = new string[0]; + + var inputData = _container + .Resolve() + .ReadFile(path); + + var resultData = _container + .Resolve() + .WordsToLowerAndRemoveBoringWords(inputData).Keys; + + resultData.Should().BeEquivalentTo(expectedData); + } + + [TearDown] + public void TearDown() + { + _graphics.Dispose(); + _bitmap.Dispose(); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer/Tests/DIContainerTests.cs b/TagsCloudContainer/TagsCloudContainer/Tests/DIContainerTests.cs new file mode 100644 index 000000000..7b542a925 --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/Tests/DIContainerTests.cs @@ -0,0 +1,44 @@ +using System.Drawing; +using Autofac; +using FluentAssertions; +using NUnit.Framework; +using TagsCloudVisualization; + +namespace TagsCloudContainer.Tests; + +[TestFixture] +public class DIContainerTests +{ + private Point _center; + private Size _imageSize; + private string _filePath = "TestData"; + private IContainer _container; + private Graphics _graphics; + private Bitmap _bitmap; + + [SetUp] + public void Setup() + { + _center = new Point(400, 400); + _imageSize = new Size(800, 800); + _bitmap = new Bitmap(_imageSize.Width, _imageSize.Height); + _graphics = Graphics.FromImage(_bitmap); + var font = new Font(FontFamily.GenericSansSerif, 20); + + _container = ContainerComposer.Compose(_center, _imageSize, _graphics, font,[]); + } + + [Test] + public void DIContainer_Resolve_CircularCloudLayouter_Test() + { + var layouter = _container.Resolve(); + layouter.Should().NotBeNull(); + } + + [TearDown] + public void TearDown() + { + _graphics.Dispose(); + _bitmap.Dispose(); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer/Tests/TXTReaderTests.cs b/TagsCloudContainer/TagsCloudContainer/Tests/TXTReaderTests.cs new file mode 100644 index 000000000..9b7425cbf --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/Tests/TXTReaderTests.cs @@ -0,0 +1,39 @@ +using FluentAssertions; +using NUnit.Framework; + +namespace TagsCloudContainer.Tests; + +[TestFixture] +public class TXTReaderTests +{ + private TxtReader _txtReader; + private string _filePath = "TestData"; + + [SetUp] + public void Setup() + { + _txtReader = new TxtReader(); + } + + [Test] + public void TXTReader_ReadFile_Should_CorrectlyReadText() + { + var expectedData = new List { "odin" }; + + var data = _txtReader.ReadFile(Path.Combine(_filePath, + "TextReader_ReadFile_Should_CorrectlyReadText.txt")); + + expectedData.Should().BeEquivalentTo(data); + } + + [Test] + public void TXTReader_ReadFile_Should_Not_ModifyText() + { + var expectedData = new List { "слово", "скучное", "в", "СЛОВО" }; + + var data = _txtReader.ReadFile(Path.Combine(_filePath, + "TXTReader_ReadFile_Should_IgnoreTextCase.txt")); + + expectedData.Should().BeEquivalentTo(data); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer/Tests/VisualizationComposerTests.cs b/TagsCloudContainer/TagsCloudContainer/Tests/VisualizationComposerTests.cs new file mode 100644 index 000000000..f10983ad8 --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/Tests/VisualizationComposerTests.cs @@ -0,0 +1,68 @@ +using System.Drawing; +using NUnit.Framework; +using Autofac; +using FluentAssertions; + +namespace TagsCloudContainer.Tests; + +[TestFixture] +public class VisualizationComposerTests +{ + private Point _center; + private Size _imageSize; + private string _filePath = "TestData"; + private IContainer _container; + private Graphics _graphics; + private Bitmap _bitmap; + + [SetUp] + public void Setup() + { + _center = new Point(400, 400); + _imageSize = new Size(800, 800); + _bitmap = new Bitmap(_imageSize.Width, _imageSize.Height); + _graphics = Graphics.FromImage(_bitmap); + var font = new Font(FontFamily.GenericSansSerif, 20); + + _container = ContainerComposer.Compose(_center, _imageSize, _graphics, font,[]); + } + + [Test] + public void VisualizationComposer_Should_ComposeDataCorrectly() + { + var path = Path.Combine(_filePath, + "VisualizationComposer_Should_ComposeDataCorrectly.txt"); + var expectedData = PrepareComposerExpectedData(path); + + var resultData = _container + .Resolve() + .ProcessFile(path, _container.Resolve()); + + expectedData.Should().BeEquivalentTo(resultData); + } + + private TextRectangleContainer[] PrepareComposerExpectedData(string path) + { + var inputData = _container + .Resolve() + .ReadFile(path); + + var data = _container + .Resolve() + .WordsToLowerAndRemoveBoringWords(inputData); + + var containers = new TextRectangleContainer[data.Count]; + var rect1 = new Rectangle(new Point(358, 383), new Size(84, 34)); + var rect2 = new Rectangle(new Point(404, 417), new Size(12, 17)); + containers[0] = new TextRectangleContainer(rect1, "слово", 1); + containers[1] = new TextRectangleContainer(rect2, "в",0.5f ); + return containers; + } + + [TearDown] + public void TearDown() + { + _graphics.Dispose(); + _bitmap.Dispose(); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer/TextRectangleContainer.cs b/TagsCloudContainer/TagsCloudContainer/TextRectangleContainer.cs new file mode 100644 index 000000000..45e0e2481 --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/TextRectangleContainer.cs @@ -0,0 +1,17 @@ +using System.Drawing; + +namespace TagsCloudContainer; + +public class TextRectangleContainer +{ + public Rectangle Rectangle { get; private set; } + public string Text { get; private set; } + public float FontSizeScale { get; private set; } + + public TextRectangleContainer(Rectangle rectangle, string text, float scale) + { + Rectangle = rectangle; + Text = text; + FontSizeScale = scale; + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer/TextRectangleContainerProcessor.cs b/TagsCloudContainer/TagsCloudContainer/TextRectangleContainerProcessor.cs new file mode 100644 index 000000000..25c302b98 --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/TextRectangleContainerProcessor.cs @@ -0,0 +1,39 @@ +using System.Drawing; +using TagsCloudVisualization; + +namespace TagsCloudContainer; + +public class TextRectangleContainerProcessor +{ + private readonly IFileReader _fileReader; + private readonly ILayouter _layouter; + private readonly RectangleSizeCalculator _rectangleSizeCalculator; + private readonly BoringWordsProcessor _boringWordsProcessor; + + public TextRectangleContainerProcessor(IFileReader fileReader, ILayouter layouter, + RectangleSizeCalculator calculator, BoringWordsProcessor boringWordsProcessor) + { + this._fileReader = fileReader; + this._layouter = layouter; + this._rectangleSizeCalculator = calculator; + this._boringWordsProcessor = boringWordsProcessor; + } + + public IEnumerable ProcessFile(string path, IWordMeasurer wordMeasurer) + { + var readData = _boringWordsProcessor.WordsToLowerAndRemoveBoringWords(_fileReader.ReadFile(path)); + + foreach (var wordInfo in readData) + { + var rectSize = _rectangleSizeCalculator.CalculateNextRectangleSize(wordInfo, wordMeasurer, out var scale); + if (rectSize == Size.Empty) + { + yield return null; + continue; + } + + var rect = _layouter.PutNextRectangle(rectSize).GetValueOrThrow(); + yield return new TextRectangleContainer(rect, wordInfo.Key, scale); + } + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer/TxtReader.cs b/TagsCloudContainer/TagsCloudContainer/TxtReader.cs new file mode 100644 index 000000000..c414c4737 --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/TxtReader.cs @@ -0,0 +1,22 @@ +using WeCantSpell.Hunspell; + +namespace TagsCloudContainer; + +internal class TxtReader : IFileReader +{ + public List ReadFile(string path) + { + var parsedWords = new List(); + using (var reader = new StreamReader(path)) + { + while (!reader.EndOfStream) + { + var line = reader.ReadLine(); + if (line is null) + continue; + parsedWords.Add(line); + } + } + return parsedWords; + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudContainer/WordMeasurer.cs b/TagsCloudContainer/TagsCloudContainer/WordMeasurer.cs new file mode 100644 index 000000000..c04957f24 --- /dev/null +++ b/TagsCloudContainer/TagsCloudContainer/WordMeasurer.cs @@ -0,0 +1,32 @@ +using System.Drawing; + +namespace TagsCloudContainer; + +public class WordMeasurer : IWordMeasurer +{ + private readonly Graphics _graphics; + private readonly Font _font; + + public WordMeasurer(Graphics graphics, Font font) + { + this._graphics = graphics; + this._font = font; + } + + public Size Measure(string word, float scale) + { + var tempFont = GetFont(scale); + var sizeF = _graphics.MeasureString(word, tempFont); + tempFont.Dispose(); + + return new Size( + (int)Math.Ceiling(sizeF.Width), + (int)Math.Ceiling(sizeF.Height) + ); + } + + public Font GetFont(float scale) + { + return new Font(_font.FontFamily, _font.Size * scale, _font.Style); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudVisualization/ArchimedeanSpiralPointGenerator.cs b/TagsCloudContainer/TagsCloudVisualization/ArchimedeanSpiralPointGenerator.cs new file mode 100644 index 000000000..a07579052 --- /dev/null +++ b/TagsCloudContainer/TagsCloudVisualization/ArchimedeanSpiralPointGenerator.cs @@ -0,0 +1,24 @@ +using System.Drawing; + +namespace TagsCloudVisualization; + +internal class ArchimedeanSpiralPointGenerator(Point start, float density) : IPointGenerator +{ + private Point _start = start; + private float _step = 0f; + private const uint MaxNumberOfPoints = UInt32.MaxValue; + private uint numberOfReturnedPoints = 0; + + public IEnumerable GetNextPoint() + { + yield return _start; + while (numberOfReturnedPoints < MaxNumberOfPoints) + { + var newX = _start.X + density * _step * (float)Math.Cos(_step); + var newY = _start.Y + density * _step * (float)Math.Sin(_step); + yield return Point.Round(new PointF(newX, newY)); + _step += 0.01f; + ++numberOfReturnedPoints; + } + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudVisualization/CircularCloudLayouter.cs b/TagsCloudContainer/TagsCloudVisualization/CircularCloudLayouter.cs new file mode 100644 index 000000000..4228bca5a --- /dev/null +++ b/TagsCloudContainer/TagsCloudVisualization/CircularCloudLayouter.cs @@ -0,0 +1,82 @@ +using System.Drawing; +using System.Runtime.CompilerServices; +using ErrorHandling; + +[assembly: InternalsVisibleTo("TagsCloudVisualizationTests")] +namespace TagsCloudVisualization; + +public class CircularCloudLayouter : ILayouter +{ + private readonly List _prevRectangles; + private readonly IPointGenerator _pointGenerator; + private readonly Rectangle _field; + private const int Density = 1; + private Point _center; + + public CircularCloudLayouter(Point center, Size fieldSize) + { + _pointGenerator = new ArchimedeanSpiralPointGenerator(center, Density); + _prevRectangles = new List(); + this._center = center; + this._field = new Rectangle(center.X - fieldSize.Width / 2, + center.Y - fieldSize.Height / 2, + fieldSize.Width, + fieldSize.Height); + } + + public IEnumerable GetLayout() + { + foreach (var rectangle in _prevRectangles) + yield return rectangle; + } + + public Result PutNextRectangle(Size rectangleSize) + { + foreach (var nextRectangleCenter in _pointGenerator.GetNextPoint()) + { + var nextRectanglePos = nextRectangleCenter - rectangleSize / 2; + if (CheckNextRectIntersection(nextRectanglePos, rectangleSize, out var nextRect)) + continue; + var pressedNextRect = new Rectangle(PressRectangleToCenter(nextRect), rectangleSize); + if (CheckIsRectOnField(pressedNextRect)) + { + _prevRectangles.Add(pressedNextRect); + return Result.Ok(pressedNextRect); + } + return Result.Fail("Слишком маленький целевой размер изображения, облако не помещается!"); + } + return Result.Fail("Слишком маленький целевой размер изображения, облако не помещается!"); + } + + internal Point PressRectangleToCenter(Rectangle rectangle) + { + var rectPos = rectangle.Location; + while (true) + { + var rectCenter = new Point( + rectPos.X + rectangle.Width / 2, + rectPos.Y + rectangle.Height / 2); + var direction = _center.Subtract(rectCenter); + if (direction == Point.Empty) + return rectPos; + var nextPos = rectPos.Add(direction); + if (CheckNextRectIntersection(nextPos, rectangle.Size, out _)) + return rectPos; + rectPos = nextPos; + } + } + + private bool CheckNextRectIntersection(Point nextPos, Size size, out Rectangle nextRect) + { + var possibleNextRect = new Rectangle(nextPos, size); + if (_prevRectangles.Any(x => x.IntersectsWith(possibleNextRect))) + { + nextRect = Rectangle.Empty; + return true; + } + nextRect = possibleNextRect; + return false; + } + + private bool CheckIsRectOnField(Rectangle rect) => _field.Contains(rect); +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudVisualization/GenerationConstants.cs b/TagsCloudContainer/TagsCloudVisualization/GenerationConstants.cs new file mode 100644 index 000000000..a357eb724 --- /dev/null +++ b/TagsCloudContainer/TagsCloudVisualization/GenerationConstants.cs @@ -0,0 +1,12 @@ +using System.Drawing; + +namespace TagsCloudVisualization; + +public static class GenerationConstants +{ + public const int CenterX = 400; + public const int CenterY = 400; + public const int DefaultRectWidth = 10; + public const int DefaultRectHeight = 20; + public const int DefaultRectNumber = 100; +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudVisualization/ILayouter.cs b/TagsCloudContainer/TagsCloudVisualization/ILayouter.cs new file mode 100644 index 000000000..d935e7319 --- /dev/null +++ b/TagsCloudContainer/TagsCloudVisualization/ILayouter.cs @@ -0,0 +1,10 @@ +using System.Drawing; +using ErrorHandling; + +namespace TagsCloudVisualization; + +public interface ILayouter +{ + public IEnumerable GetLayout(); + public Result PutNextRectangle(Size rectangleSize); +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudVisualization/IPointGenerator.cs b/TagsCloudContainer/TagsCloudVisualization/IPointGenerator.cs new file mode 100644 index 000000000..9a524785c --- /dev/null +++ b/TagsCloudContainer/TagsCloudVisualization/IPointGenerator.cs @@ -0,0 +1,8 @@ +using System.Drawing; + +namespace TagsCloudVisualization; + +internal interface IPointGenerator +{ + public IEnumerable GetNextPoint(); +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudVisualization/PointExtensions.cs b/TagsCloudContainer/TagsCloudVisualization/PointExtensions.cs new file mode 100644 index 000000000..6bc692e48 --- /dev/null +++ b/TagsCloudContainer/TagsCloudVisualization/PointExtensions.cs @@ -0,0 +1,16 @@ +using System.Drawing; + +namespace TagsCloudVisualization; + +public static class PointExtensions +{ + public static Point Subtract(this Point point, Point other) + { + return new Point(point.X - other.X, point.Y - other.Y); + } + + public static Point Add(this Point point, Point other) + { + return new Point(point.X + other.X, point.Y + other.Y); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudVisualization/RectangleExtensions.cs b/TagsCloudContainer/TagsCloudVisualization/RectangleExtensions.cs new file mode 100644 index 000000000..aa25aea9f --- /dev/null +++ b/TagsCloudContainer/TagsCloudVisualization/RectangleExtensions.cs @@ -0,0 +1,9 @@ +using System.Drawing; + +namespace TagsCloudVisualization; + +public static class RectangleExtensions +{ + public static Point GetCenter(this Rectangle rectangle) => + rectangle.Location + rectangle.Size / 2; +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudVisualization/Result.cs b/TagsCloudContainer/TagsCloudVisualization/Result.cs new file mode 100644 index 000000000..ea8dcb099 --- /dev/null +++ b/TagsCloudContainer/TagsCloudVisualization/Result.cs @@ -0,0 +1,101 @@ +using System; + +namespace ErrorHandling; + +public class None +{ + private None() + { + } +} + +public struct Result +{ + public Result(string error, T value = default(T)) + { + Error = error; + Value = value; + } + + public string Error { get; } + internal T Value { get; } + + public T GetValueOrThrow() + { + if (IsSuccess) return Value; + throw new InvalidOperationException($"No value. Only Error {Error}"); + } + + public bool IsSuccess => Error == null; +} + +public static class Result +{ + public static Result AsResult(this T value) + { + return Ok(value); + } + + public static Result Ok(T value) + { + return new Result(null, value); + } + + public static Result Fail(string e) + { + return new Result(e); + } + + public static Result Of(Func f, string error = null) + { + try + { + return Ok(f()); + } + catch (Exception e) + { + return Fail(error ?? e.Message); + } + } + + public static Result Then( + this Result input, + Func continuation) + { + return Then(input, (inp) => Of(() => continuation(inp))); + } + + public static Result Then( + this Result input, + Func> continuation) + { + if (input.IsSuccess) + return continuation(input.Value); + return Fail(input.Error); + } + + public static Result OnFail( + this Result input, + Action handleError) + { + if (!input.IsSuccess) + handleError(input.Error); + return input; + } + + public static Result ReplaceError( + this Result input, + Func continuation) + { + if (!input.IsSuccess) + return Fail(continuation(input.Value)); + return input; + } + + public static Result RefineError( + this Result input, + string refine) + { + return input.ReplaceError((x) => $"{refine}. {input.Error}"); + } +} \ No newline at end of file diff --git a/TagsCloudContainer/TagsCloudVisualization/TagsCloudVisualization.csproj b/TagsCloudContainer/TagsCloudVisualization/TagsCloudVisualization.csproj new file mode 100644 index 000000000..135d1a5a0 --- /dev/null +++ b/TagsCloudContainer/TagsCloudVisualization/TagsCloudVisualization.csproj @@ -0,0 +1,10 @@ + + + + Library + net8.0 + enable + enable + + + diff --git a/TagsCloudContainer/custom.bmp b/TagsCloudContainer/custom.bmp new file mode 100644 index 000000000..a754a1eb6 Binary files /dev/null and b/TagsCloudContainer/custom.bmp differ diff --git a/TagsCloudContainer/global.json b/TagsCloudContainer/global.json new file mode 100644 index 000000000..2ddda36c2 --- /dev/null +++ b/TagsCloudContainer/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "8.0.0", + "rollForward": "latestMinor", + "allowPrerelease": false + } +} \ No newline at end of file diff --git a/TagsCloudContainer/output.bmp b/TagsCloudContainer/output.bmp new file mode 100644 index 000000000..4fb7b14a7 Binary files /dev/null and b/TagsCloudContainer/output.bmp differ diff --git a/TagsCloudContainer/text.txt b/TagsCloudContainer/text.txt new file mode 100644 index 000000000..0011fa4e7 --- /dev/null +++ b/TagsCloudContainer/text.txt @@ -0,0 +1,7 @@ +слово +СКУЧноЕ +скучное +в +СЛОВО +СКУЧНОЕ +СКУЧНОЕ \ No newline at end of file diff --git a/TagsCloudContainer/text1.txt b/TagsCloudContainer/text1.txt new file mode 100644 index 000000000..c4b2dbbed --- /dev/null +++ b/TagsCloudContainer/text1.txt @@ -0,0 +1,5000 @@ +Полный +по +HTML +Функция +Статья +Веб +на +Синтаксис +Блог +на +Новость +Тестирование +Веб +Репозиторий +Интеллект +Приложение +что +Стек +Нейросеть +Игра +но +не +Веб +в +на +от +HTML +Алгоритм +Дизайн +Дизайн +также +Функция +Игра +CSS +Пакет +Данные +Анализ +также +Игра +как +как +Метка +Код +SQL +не +Категория +Облако +на +на +Регистрация +Искусственный +Поиск +Мобильное +Репозиторий +Пакет +Репозиторий +от +от +Новость +Слово_266 +Слово_358 +Сайт +Версия +Система +на +Данные +Полный +Сайт +Сервер +от +Ошибка +как +это +как +Стек +что +в +Данных +или +Разработка +Алгоритм +Стек +для +не +не +Обучение +CSS +SQL +в +Анализ +Анализ +Версия +в +и +SQL +Фильтр +Нейросеть +Алгоритм +что +CSS +не +Интерфейс +с +это +это +Код +в +на +Менеджер +Контроль +SQL +Блог +Контроль +в +JavaScript +Библиотека +CSS +Дизайн +Обучение +Игра +Python +или +что +также +Слово_466 +Слово_449 +также +Python +от +Интеллект +Категория +Анализ +для +Библиотека +Ошибка +Блог +Логин +Нейросеть +это +что +Java +Java +Ветка +Git +База +от +Контроль +Настройка +но +также +Java +на +но +Клиент +Система +Python +Статья +Тестирование +Блог +Python +Фреймворк +Java +от +с +как +C++ +Слово_281 +Менеджер +по +Git +для +Функция +Репозиторий +Нейросеть +но +Клиент +с +Контроль +Оптимизация +и +Данные +Фильтр +Приложение +не +с +Пакет +Полный +Git +Алгоритм +Профиль +Полный +Синтаксис +Фронтенд +Шифрование +Библиотека +SQL +или +Приложение +Сервер +Искусственный +это +и +Слово_147 +по +Искусственный +HTML +Интерфейс +Git +с +SQL +Слово_108 +База +Тестирование +не +Ветка +Разработка +что +и +Ошибка +Код +с +Синтаксис +Слово_141 +также +также +Разработка +Версия +Фреймворк +не +на +что +Система +Функция +Слово_238 +Слово_286 +Игра +от +Интерфейс +Слово_307 +Тестирование +также +Анализ +или +Java +Версия +для +Python +это +Функция +Новость +Искусственный +не +Тестирование +Функция +Настройка +но +Метка +Сайт +и +HTML +Фреймворк +Библиотека +это +Веб +Код +Контроль +Слово_162 +Фреймворк +Менеджер +Искусственный +Функция +База +Облако +Слово_270 +на +как +Приложение +Запрос +на +Админ +JavaScript +с +Дата +на +Функция +Библиотека +Приложение +Слово_299 +Время +в +также +или +или +Анализ +Фреймворк +Клиент +также +Версия +Слово_239 +также +от +Дата +и +это +для +Интеллект +Пользователь +Обучение +Сайт +Синтаксис +Шифрование +но +Слово_196 +Пользователь +Время +Контроль +или +Настройка +Алгоритм +Обучение +Слово_108 +Категория +Мобильное +Слово_177 +Нейросеть +Статья +Приложение +Клиент +SQL +Профиль +Статья +и +Обучение +Искусственный +Логин +не +Система +Веб +Нейросеть +Код +Полный +не +Слово_494 +в +Сайт +Игра +Приложение +Данные +Поиск +База +Мобильное +от +на +Слово_255 +в +Веб +Дата +Сайт +с +Дизайн +это +Git +Git +что +Слово_499 +Игра +Python +Приложение +что +Дата +по +Слово_283 +Логин +Слово_114 +Библиотека +Настройка +это +Функция +и +или +Пакет +Алгоритм +Бэкенд +Запрос +Репозиторий +Сайт +Интеллект +Java +Регистрация +Блог +JavaScript +Нейросеть +Настройка +или +HTML +Данные +Контроль +Дизайн +или +как +Менеджер +Сортировка +но +Слово_316 +Ветка +Категория +на +в +Java +от +Код +Алгоритм +Интерфейс +Панель +Дата +Алгоритм +Игра +Пароль +Анализ +Система +с +что +в +Веб +Система +Веб +Приложение +Разработка +Интерфейс +Код +что +и +Слово_372 +Бэкенд +Тестирование +на +Данных +C++ +Бэкенд +Облако +Репозиторий +CSS +Репозиторий +Версия +C++ +Интеллект +HTML +Стек +Тег +Веб +Анализ +Интерфейс +HTML +Python +по +C++ +Слово_106 +База +Менеджер +Python +Интеллект +на +что +Бэкенд +Слово_160 +Тестирование +Код +Репозиторий +что +на +Полный +это +Пользователь +не +с +Слово_492 +Сайт +в +Искусственный +Запрос +Фильтр +в +Метка +что +Пароль +что +Дизайн +Синтаксис +с +как +Фреймворк +Безопасность +что +Пакет +Интерфейс +Приложение +это +Обучение +с +от +Слово_424 +Тестирование +Код +Регистрация +что +Регистрация +Шифрование +Игра +для +База +Нейросеть +Слово_242 +Git +не +Регистрация +от +Клиент +с +не +Искусственный +для +HTML +Дата +Анализ +Статья +Система +с +Поиск +JavaScript +Клиент +Клиент +Дизайн +не +Категория +Контроль +как +Искусственный +Админ +SQL +Тестирование +по +что +Стек +также +что +Версия +с +Вход +Запрос +от +по +Игра +Искусственный +как +SQL +Веб +но +и +также +по +и +Тестирование +Слово_216 +Сайт +Данные +на +Сортировка +Шифрование +Запрос +на +от +Тестирование +Дизайн +Категория +Пакет +но +для +Игра +от +Контроль +Сервер +как +CSS +Слово_244 +Искусственный +Вход +Вход +Пакет +Шифрование +на +Безопасность +Слово_236 +как +но +Статья +Тег +Слово_354 +Категория +Слово_117 +это +Слово_152 +или +Фильтр +это +Профиль +Интеллект +SQL +но +Мобильное +с +также +Слово_415 +также +Библиотека +Панель +Панель +это +на +по +Алгоритм +но +Интеллект +Библиотека +SQL +и +Регистрация +это +как +но +Сортировка +от +для +в +Слово_114 +Алгоритм +Приложение +по +Фреймворк +в +Слово_133 +это +Игра +Настройка +Игра +CSS +Веб +Фильтр +Контроль +или +Слово_245 +Категория +Репозиторий +в +Алгоритм +Шифрование +Запрос +Безопасность +в +с +Python +по +Искусственный +в +Интеллект +Клиент +что +на +Шифрование +Код +Нейросеть +Слово_497 +JavaScript +также +Слово_160 +Сервер +Репозиторий +для +Сайт +C++ +как +Интерфейс +C++ +с +Мобильное +с +Фреймворк +Репозиторий +не +Синтаксис +как +Git +Данных +Тестирование +JavaScript +Система +также +но +Ошибка +Ветка +по +Веб +Git +Дата +Слово_399 +Git +Оптимизация +Алгоритм +Менеджер +Регистрация +но +CSS +Панель +Админ +Ветка +Анализ +что +от +Python +на +Сервер +Искусственный +как +на +Метка +Фреймворк +Слово_229 +также +Вход +Сайт +Обучение +Код +от +Веб +JavaScript +Тег +Мобильное +Сортировка +Полный +Категория +на +как +от +Система +но +также +Анализ +как +Ошибка +Веб +Категория +Блог +Разработка +Данные +Тестирование +Профиль +Данные +SQL +Профиль +с +Код +Искусственный +это +для +Слово_367 +на +не +это +Синтаксис +Сайт +Слово_269 +это +Менеджер +Искусственный +JavaScript +Python +по +Пакет +Код +Функция +Веб +Система +HTML +Разработка +Тестирование +Сортировка +на +Оптимизация +и +в +Клиент +Категория +Дизайн +Репозиторий +также +но +Клиент +и +это +Версия +Python +от +Фронтенд +Тестирование +Блог +База +Данных +Менеджер +но +не +Ветка +Сортировка +SQL +что +Дата +но +Запрос +с +Нейросеть +по +Git +Анализ +Фронтенд +Искусственный +Функция +Приложение +как +Python +Java +или +на +или +Слово_109 +для +для +Алгоритм +по +Шифрование +но +в +Клиент +Git +это +Фильтр +Фреймворк +Данные +Нейросеть +База +что +Данные +HTML +Python +Код +Фильтр +как +и +Менеджер +Код +с +Запрос +Слово_288 +Дизайн +в +что +Сайт +Система +Обучение +Слово_401 +Стек +Логин +что +но +Тестирование +как +Данные +Панель +от +по +Безопасность +как +Статья +Мобильное +C++ +на +с +это +Искусственный +Интерфейс +CSS +Репозиторий +Дизайн +C++ +Нейросеть +что +также +Слово_200 +Python +Слово_248 +для +Админ +Система +База +C++ +Полный +Блог +Пользователь +и +JavaScript +Вход +Слово_302 +от +Функция +Версия +это +HTML +Блог +Нейросеть +для +не +и +Код +Приложение +Полный +с +Приложение +Запрос +это +Версия +как +или +и +не +с +или +по +Слово_399 +Дата +не +это +Сервер +Интерфейс +Ошибка +Сайт +Git +как +Стек +Блог +Фильтр +что +Нейросеть +Клиент +Менеджер +это +Клиент +Сервер +это +Фреймворк +Версия +что +Python +по +для +Блог +Обучение +не +JavaScript +это +не +Клиент +в +Анализ +Слово_206 +по +Игра +на +Интеллект +для +Приложение +Админ +Дизайн +по +Данные +это +в +Мобильное +Слово_358 +по +Библиотека +для +Интерфейс +Библиотека +Игра +или +Фреймворк +C++ +для +от +Данные +Обучение +или +Дизайн +Фронтенд +что +Система +Репозиторий +Метка +C++ +Мобильное +Данные +Сервер +Нейросеть +это +также +Тестирование +не +C++ +Дизайн +Полный +Приложение +Git +Пакет +или +Оптимизация +и +для +Регистрация +но +Профиль +База +Java +также +в +Версия +Клиент +Репозиторий +по +Слово_416 +Мобильное +Данные +Блог +Дизайн +как +Сайт +с +Данные +для +Функция +на +Данные +Клиент +Сайт +Веб +для +Слово_280 +Данные +Нейросеть +на +Интерфейс +на +Искусственный +или +но +не +Мобильное +Вход +Данных +по +также +Нейросеть +не +Пакет +Искусственный +по +Анализ +SQL +Алгоритм +Фреймворк +и +что +с +Функция +Логин +База +Ошибка +Пользователь +JavaScript +Время +от +Сортировка +но +также +Нейросеть +JavaScript +Админ +для +Разработка +Игра +Данные +Оптимизация +по +Админ +Ветка +Функция +Данные +Искусственный +Стек +Git +это +Сайт +Искусственный +также +и +Данные +Веб +не +Интеллект +с +Сайт +Нейросеть +Полный +с +для +Статья +Мобильное +для +HTML +но +как +от +HTML +для +Категория +Искусственный +с +Настройка +Фильтр +что +в +с +в +с +по +Репозиторий +Фреймворк +от +Метка +Веб +База +Java +База +для +Git +Клиент +от +это +по +с +Слово_111 +Обучение +или +как +и +не +Блог +но +по +с +Сайт +Слово_283 +Фильтр +Шифрование +Ошибка +Обучение +Логин +C++ +также +Библиотека +Ошибка +Полный +Система +или +Git +Категория +Время +Вход +SQL +Система +Интеллект +не +Сайт +что +как +Данных +Версия +Python +SQL +Функция +Репозиторий +Слово_402 +что +Анализ +Полный +Тестирование +Слово_485 +Ветка +Фреймворк +Профиль +Шифрование +для +Метка +База +на +Алгоритм +Слово_282 +Python +Искусственный +также +с +но +Слово_125 +Приложение +Ветка +как +Анализ +с +но +Слово_252 +не +но +это +от +HTML +Искусственный +от +Сервер +по +для +Версия +на +не +не +по +от +Репозиторий +Функция +для +в +Новость +Стек +Облако +Python +Нейросеть +как +Ветка +Клиент +Приложение +но +не +Мобильное +Данные +Фреймворк +Обучение +на +как +Нейросеть +Сайт +что +Искусственный +Анализ +Контроль +Нейросеть +это +JavaScript +Тестирование +Оптимизация +Стек +и +Админ +Данные +Пользователь +JavaScript +Интерфейс +Менеджер +CSS +или +Регистрация +с +Пароль +Сервер +для +Python +Функция +Слово_484 +Слово_280 +с +Интеллект +Обучение +в +по +Данных +Приложение +Git +Запрос +Алгоритм +это +Данные +Запрос +также +Java +в +Версия +Шифрование +Слово_500 +от +от +также +с +Время +Приложение +Менеджер +или +Анализ +от +Код +как +с +Слово_407 +на +Версия +SQL +Библиотека +Анализ +Панель +Слово_264 +Дата +Дизайн +Игра +Менеджер +но +Сервер +Статья +Разработка +Искусственный +Менеджер +или +также +не +Приложение +Слово_488 +Код +для +Ветка +но +База +это +Искусственный +HTML +Нейросеть +для +HTML +Слово_414 +Пакет +также +Синтаксис +HTML +Фреймворк +Система +Обучение +Библиотека +Разработка +Слово_193 +Веб +Фильтр +Приложение +Алгоритм +по +Интеллект +Игра +CSS +Git +Приложение +Интеллект +в +что +Код +как +Код +но +Python +также +Нейросеть +Профиль +Фронтенд +Код +Репозиторий +Статья +C++ +как +также +не +Анализ +Пакет +Логин +Оптимизация +Функция +Приложение +что +Функция +Java +Тестирование +также +это +Панель +с +Алгоритм +Тег +Облако +Слово_422 +Слово_231 +Искусственный +C++ +что +на +но +Слово_106 +Стек +Слово_300 +Полный +JavaScript +это +или +JavaScript +Ошибка +Код +в +по +как +Менеджер +в +Менеджер +Веб +или +Слово_250 +Java +что +для +Данных +Git +Библиотека +с +для +Тег +Анализ +не +в +это +что +Python +CSS +не +JavaScript +Анализ +CSS +Анализ +в +Нейросеть +Дата +что +Игра +Слово_139 +но +Слово_273 +Нейросеть +Тестирование +Данные +Контроль +Git +CSS +Обучение +от +Ошибка +также +или +в +как +Интеллект +Пакет +Пароль +что +Категория +на +не +Контроль +от +Блог +Регистрация +Алгоритм +Слово_360 +Пакет +Алгоритм +Безопасность +JavaScript +Ветка +Python +Слово_323 +Сайт +Слово_432 +Код +Ветка +как +Регистрация +Нейросеть +Статья +Клиент +Код +но +как +Код +но +Git +также +Новость +также +Java +Фреймворк +Версия +не +от +Данных +с +Интеллект +Синтаксис +Данные +Обучение +Веб +Слово_105 +Слово_303 +Настройка +Библиотека +как +Разработка +Алгоритм +HTML +Искусственный +Пакет +Фильтр +C++ +по +для +HTML +Стек +также +C++ +Python +Репозиторий +Игра +Java +Логин +JavaScript +но +Алгоритм +Пакет +Система +Запрос +Разработка +Слово_160 +Пароль +Java +Пользователь +База +C++ +Приложение +Ветка +также +как +в +для +Пакет +Python +C++ +JavaScript +Данных +CSS +Веб +Интеллект +также +Слово_174 +но +Данные +Анализ +по +Новость +C++ +Интерфейс +также +по +Клиент +Искусственный +Python +Искусственный +также +JavaScript +Версия +с +Интерфейс +Ошибка +Дизайн +Система +или +как +не +Запрос +Тег +Фильтр +Ветка +Тестирование +Ветка +Java +Репозиторий +от +Сайт +Анализ +и +Веб +это +Слово_472 +Интерфейс +Логин +Система +или +Фреймворк +Данных +но +Настройка +SQL +для +Мобильное +это +на +Категория +Тестирование +по +Система +с +как +в +Настройка +JavaScript +Сайт +Обучение +C++ +Пакет +Git +Контроль +Репозиторий +Тег +как +или +Пользователь +от +что +что +Java +Пакет +Слово_484 +Веб +Код +от +Функция +Искусственный +Ошибка +как +Полный +Искусственный +База +Код +Слово_203 +Версия +Время +Система +Слово_236 +и +от +от +с +от +Тестирование +Метка +Статья +для +HTML +и +Интеллект +Фреймворк +Интерфейс +Контроль +Код +Данные +Интерфейс +База +в +Разработка +также +это +Сервер +Обучение +не +Игра +и +Стек +с +Контроль +что +Функция +Фреймворк +или +Пакет +от +в +Бэкенд +Данные +также +Репозиторий +с +Искусственный +от +но +Обучение +что +Дизайн +Шифрование +также +Искусственный +Дизайн +Сервер +от +Фронтенд +Тег +Функция +Игра +для +Дизайн +Поиск +Функция +C++ +Разработка +Разработка +Ошибка +Версия +Слово_217 +Слово_495 +SQL +Python +Фронтенд +Логин +также +JavaScript +CSS +как +с +Функция +на +не +или +в +CSS +Облако +Фильтр +для +Функция +Сортировка +Тестирование +База +в +Слово_258 +Интерфейс +Сортировка +Фреймворк +на +Нейросеть +База +в +или +Сайт +Версия +Git +с +Система +Разработка +Ошибка +с +Дизайн +Фронтенд +это +как +по +также +Мобильное +Облако +Пакет +Фронтенд +или +по +Пароль +Алгоритм +Интерфейс +на +Фреймворк +Обучение +Админ +также +по +Админ +Игра +Пакет +по +что +как +Бэкенд +от +C++ +что +Клиент +База +по +Репозиторий +CSS +Библиотека +Метка +HTML +CSS +Слово_375 +Репозиторий +Контроль +Сайт +Данные +Сервер +Полный +Функция +не +CSS +по +Код +в +Синтаксис +Приложение +Сервер +Библиотека +Менеджер +что +Версия +в +C++ +Пользователь +Интерфейс +Синтаксис +это +Слово_422 +но +для +Функция +Нейросеть +что +на +Интеллект +на +это +Слово_488 +и +Настройка +как +Функция +что +Облако +также +Игра +по +Функция +Регистрация +Искусственный +с +Безопасность +также +Веб +Разработка +по +но +Разработка +Веб +Приложение +JavaScript +но +с +от +Git +и +Разработка +Искусственный +это +в +по +Слово_352 +как +это +по +Нейросеть +не +Веб +Оптимизация +Обучение +это +не +от +на +Git +Админ +это +Сортировка +не +Мобильное +в +что +База +Система +это +Данные +или +с +Код +и +как +Поиск +Слово_256 +Ошибка +Слово_159 +Тег +это +Искусственный +Дизайн +Обучение +по +Слово_372 +Интерфейс +Контроль +SQL +Система +также +SQL +Слово_409 +также +Репозиторий +Интеллект +по +Оптимизация +Данных +что +Сервер +Сайт +Python +в +Анализ +Тестирование +Приложение +Git +по +Дизайн +и +Тег +как +C++ +База +Веб +в +Игра +Клиент +Логин +Полный +Слово_125 +от +Обучение +также +Бэкенд +или +Статья +Метка +Версия +Алгоритм +это +Алгоритм +Дизайн +Библиотека +Тег +для +Новость +Блог +C++ +на +также +по +на +Версия +Код +Сервер +Новость +JavaScript +Блог +для +Нейросеть +База +Код +Слово_177 +Анализ +не +Слово_360 +Слово_161 +Ветка +Обучение +Версия +от +Веб +что +Блог +Python +не +Слово_263 +Данных +Админ +как +Функция +в +но +Блог +Фильтр +Обучение +C++ +Python +на +Слово_145 +Анализ +также +Алгоритм +Слово_446 +это +также +Игра +от +Ветка +Интеллект +Веб +Слово_485 +Пакет +Фреймворк +Тег +как +Пользователь +как +Слово_364 +по +Алгоритм +Анализ +Нейросеть +Время +для +Нейросеть +Игра +JavaScript +Игра +База +Облако +Нейросеть +Ошибка +Тестирование +но +Сервер +Код +Git +Функция +Приложение +Тестирование +Искусственный +Запрос +Пакет +Тестирование +от +Дизайн +Нейросеть +Пакет +Контроль +с +Обучение +как +Контроль +Искусственный +в +но +Разработка +что +не +Анализ +Фронтенд +Ветка +Пакет +с +Данные +Слово_308 +или +Код +Облако +Контроль +Слово_118 +в +Функция +не +Слово_244 +Стек +Слово_258 +не +не +как +Данных +Фронтенд +или +Анализ +Настройка +Репозиторий +C++ +Пакет +Профиль +Интеллект +Время +что +Пакет +Сервер +Код +Пакет +это +Ошибка +с +Вход +в +на +Пользователь +Запрос +это +Данных +Время +как +Время +Библиотека +не +CSS +Нейросеть +также +Веб +Алгоритм +Синтаксис +или +с +как +Игра +Слово_355 +Пользователь +для +Анализ +Фильтр +не +или +что +Менеджер +не +Поиск +Репозиторий +Разработка +Код +также +по +не +Python +Анализ +Пакет +Разработка +Клиент +Репозиторий +это +Админ +Функция +Алгоритм +Шифрование +и +Менеджер +для +что +Шифрование +Тестирование +Интерфейс +CSS +Python +по +это +Логин +Ошибка +Библиотека +Оптимизация +это +и +или +Приложение +и +что +Слово_115 +Ошибка +CSS +CSS +Обучение +Логин +Обучение +и +Менеджер +Пользователь +Пароль +Мобильное +это +Git +как +Дизайн +Дизайн +Контроль +Библиотека +Игра +CSS +Python +Анализ +Мобильное +C++ +на +Время +Игра +Пакет +Git +Интеллект +SQL +не +Тестирование +по +CSS +Git +как +от +от +Интеллект +также +Код +Алгоритм +Контроль +Git +Слово_189 +Анализ +CSS +что +в +Библиотека +Обучение +Слово_308 +Время +JavaScript +но +Сервер +HTML +HTML +в +на +также +для +Интерфейс +в +это +это +Сервер +Статья +Слово_262 +Git +что +Настройка +Сервер +Код +Синтаксис +на +от +Настройка +но +Фронтенд +JavaScript +это +также +Полный +CSS +как +Интерфейс +Функция +не +не +Git +Версия +HTML +в +Статья +Веб +что +также +по +База +Менеджер +Дата +в +Java +Игра +Шифрование +Ошибка +Оптимизация +от +Слово_168 +C++ +Оптимизация +Шифрование +Обучение +SQL +Java +JavaScript +Python +Репозиторий +в +Ветка +в +Синтаксис +Пароль +на +Система +для +Git +не +Ошибка +Блог +CSS +но +Мобильное +как +для +SQL +Разработка +Данные +Стек +Алгоритм +Интеллект +Веб +это +Тестирование +Контроль +Поиск +Система +или +JavaScript +Поиск +Разработка +на +Алгоритм +JavaScript +но +Интеллект +Ошибка +Синтаксис +для +SQL +для +Сайт +Бэкенд +Библиотека +это +что +CSS +Сервер +Категория +Приложение +Запрос +Полный +Пакет +Веб +Тестирование +Синтаксис +Контроль +Алгоритм +Тестирование +это +от +также +Интеллект +как +Разработка +SQL +Клиент +Контроль +База +Ошибка +это +JavaScript +не +или +HTML +по +Интеллект +Python +Клиент +это +Алгоритм +не +Логин +Python +в +Слово_477 +Слово_105 +Тег +Сервер +Дизайн +и +Тег +Контроль +Python +также +Контроль +Разработка +C++ +от +Фреймворк +Бэкенд +HTML +Профиль +Дизайн +Контроль +Python +с +Слово_395 +или +Метка +Библиотека +Пользователь +Java +SQL +Регистрация +но +Игра +Репозиторий +Новость +Стек +но +Дата +Приложение +Анализ +или +Обучение +также +Git +но +Облако +Мобильное +Слово_224 +Слово_342 +Система +Искусственный +Обучение +Сайт +HTML +на +что +на +также +Искусственный +с +SQL +Фреймворк +Пароль +Облако +но +Админ +по +Нейросеть +Логин +Слово_402 +Панель +Слово_332 +Админ +Сервер +как +по +Алгоритм +Анализ +CSS +Запрос +Ошибка +Бэкенд +Искусственный +Безопасность +от +Библиотека +Тестирование +Время +Бэкенд +Фронтенд +Код +Разработка +Анализ +на +с +Слово_138 +Сортировка +Приложение +Клиент +с +CSS +на +SQL +это +Слово_248 +JavaScript +Веб +Тестирование +Нейросеть +по +Регистрация +Веб +для +Git +Пакет +Фреймворк +Бэкенд +Время +Тестирование +Алгоритм +как +Функция +также +Синтаксис +для +по +также +Java +Слово_122 +как +Ошибка +Дата +Функция +не +с +Тег +Слово_319 +Пакет +Обучение +для +Метка +Алгоритм +Алгоритм +Клиент +Нейросеть +Репозиторий +JavaScript +Сервер +в +от +это +База +Метка +Слово_173 +Админ +с +Нейросеть +по +не +Код +это +и +C++ +Анализ +Менеджер +Git +Слово_412 +что +Git +Интеллект +что +также +JavaScript +Алгоритм +Сортировка +Слово_308 +База +также +Логин +Новость +по +Настройка +в +Тестирование +База +SQL +Система +Данных +от +не +Ошибка +Сортировка +Репозиторий +Бэкенд +или +Нейросеть +Библиотека +с +для +Шифрование +База +Слово_281 +Стек +Версия +Запрос +на +Мобильное +Новость +Система +с +также +Веб +Регистрация +Слово_312 +Данные +Алгоритм +Ветка +для +Слово_331 +Git +с +Функция +по +Клиент +Слово_112 +Сайт +Интеллект +это +для +Админ +Контроль +Безопасность +Java +для +Логин +SQL +Пароль +Логин +CSS +и +CSS +не +в +что +Стек +Бэкенд +Алгоритм +по +в +Нейросеть +с +также +от +также +на +в +Тестирование +JavaScript +Менеджер +Git +Сайт +Функция +с +на +Игра +Мобильное +но +HTML +Синтаксис +Данные +Код +C++ +Тестирование +но +в +также +Метка +Блог +HTML +Версия +Git +в +Пользователь +также +также +Фреймворк +JavaScript +Искусственный +Клиент +это +Пароль +Тестирование +Ошибка +Сервер +как +это +с +Функция +JavaScript +JavaScript +C++ +Данные +Данные +Контроль +Разработка +Git +Слово_130 +Сервер +JavaScript +Синтаксис +но +для +HTML +Менеджер +CSS +Фильтр +Сайт +База +Код +JavaScript +Слово_228 +Ветка +Полный +Нейросеть +Тестирование +Тег +Функция +Сервер +с +Git +Оптимизация +Функция +Регистрация +для +и +Новость +как +Клиент +также +Слово_166 +Ошибка +на +Версия +на +Дизайн +Дата +Поиск +на +Функция +Репозиторий +SQL +Искусственный +и +от +Интеллект +не +Фреймворк +Репозиторий +с +Анализ +Метка +от +Статья +База +с +Код +Менеджер +Алгоритм +Поиск +что +Версия +по +с +от +не +Сайт +Пароль +как +от +что +в +Данные +это +Слово_312 +от +также +Приложение +не +Данных +в +также +Функция +Нейросеть +но +по +как +что +также +Разработка +Запрос +но +HTML +Анализ +Вход +Версия +Данные +или +для +или +от +Облако +Дизайн +но +по +Слово_206 +или +или +Версия +Репозиторий +Искусственный +как +Сайт +Приложение +Интерфейс +но +Ветка +Разработка +но +Слово_368 +на +Сервер +Приложение +Слово_201 +Синтаксис +с +Поиск +Интерфейс +Библиотека +Python +Система +Интерфейс +или +C++ +SQL +JavaScript +что +в +или +как +Интеллект +но +также +Система +JavaScript +и +не +Безопасность +но +или +это +Фреймворк +База +Тестирование +в +CSS +Слово_466 +Python +но +от +что +не +Интеллект +в +Python +Git +Время +Алгоритм +Контроль +Веб +Контроль +но +Веб +Библиотека +Контроль +Ветка +Ветка +CSS +Искусственный +Мобильное +или +Репозиторий +Нейросеть +База +и +Метка +Слово_135 +Метка +не +Фреймворк +Слово_455 +JavaScript +Интеллект +JavaScript +Поиск +но +Фреймворк +и +также +Интерфейс +Анализ +это +Искусственный +с +Тег +База +на +это +База +как +Интерфейс +Безопасность +Сайт +Блог +Данных +Менеджер +Синтаксис +База +Ветка +Интерфейс +также +Ошибка +по +Git +Java +Регистрация +это +также +Облако +Анализ +Ошибка +HTML +Ошибка +Слово_449 +Git +но +по +Сайт +Менеджер +Разработка +Слово_231 +и +Сайт +Данных +что +Слово_487 +это +Слово_252 +также +в +Репозиторий +как +Сайт +Код +в +на +по +на +от +это +по +Слово_235 +Ошибка +но +Стек +Панель +Контроль +Java +Игра +Игра +Разработка +или +Git +по +Версия +Тег +Пакет +не +Нейросеть +и +Java +или +и +Пакет +Контроль +или +Ошибка +это +Обучение +Данные +Слово_295 +Новость +CSS +Тестирование +что +Python +Нейросеть +что +Фреймворк +Слово_494 +в +Безопасность +Разработка +C++ +Библиотека +на +Git +но +также +это +Блог +и +Метка +или +Стек +Стек +как +Контроль +Интеллект +Полный +Интерфейс +Админ +или +Интерфейс +Вход +Слово_284 +как +по +Ветка +Обучение +Слово_365 +Ветка +Синтаксис +Поиск +HTML +Ветка +также +Код +Слово_483 +SQL +также +Код +Функция +Функция +Обучение +Менеджер +Бэкенд +Регистрация +Админ +как +Обучение +Контроль +Java +Данные +на +Система +Тестирование +Интеллект +C++ +Игра +Библиотека +Ветка +Python +Версия +Разработка +и +Дизайн +Слово_413 +HTML +Java +не +Время +Дизайн +Менеджер +по +HTML +для +Время +Java +и +Ошибка +JavaScript +по +Веб +Дизайн +Система +в +Обучение +Интерфейс +Данные +как +и +это +Фронтенд +что +Регистрация +Интеллект +но +это +Вход +Мобильное +Нейросеть +Клиент +Нейросеть +JavaScript +Версия +Игра +Java +на +Метка +и +Новость +Новость +Тег +с +Система +также +База +но +Клиент +Фреймворк +Данные +Игра +Анализ +от +Стек +Искусственный +Контроль +Интерфейс +от +не +Алгоритм +на +JavaScript +Код +Мобильное +Интерфейс +но +от +Дата +но +на +Слово_262 +с +не +не +Библиотека +Слово_247 +что +также +для +Сайт +с +Нейросеть +на +Блог +для +Настройка +Поиск +что +Пароль +Новость +Разработка +Интеллект +в +Поиск +но +что +как +Git +Java +Игра +База +Разработка +Сайт +от +в +Код +для +Данные +Код +также +База +для +но +Оптимизация +Бэкенд +Вход +Сервер +не +Фреймворк +в +но +это +Обучение +по +Запрос +от +от +Категория +и +что +Ошибка +Сортировка +для +CSS +Клиент +Искусственный +Панель +Сервер +или +База +Веб +Слово_420 +Слово_296 +но +Регистрация +Полный +также +Слово_254 +в +Мобильное +но +Клиент +C++ +Нейросеть +или +не +или +Пароль +Разработка +Пакет +Git +на +с +HTML +Git +Менеджер +HTML +но +но +Репозиторий +Приложение +с +Блог +и +но +не +Python +на +это +Система +и +в +SQL +Слово_286 +База +Настройка +Фреймворк +Логин +Слово_274 +с +Данные +Безопасность +что +что +Оптимизация +Код +Поиск +Пароль +что +Тестирование +Ошибка +Данные +Оптимизация +Панель +Сайт +Нейросеть +также +Профиль +и +Код +Слово_334 +Контроль +Время +не +по +Python +HTML +Сервер +JavaScript +на +HTML +Версия +но +Данные +также +Слово_178 +и +C++ +или +от +HTML +Слово_324 +Версия +Фреймворк +как +не +Слово_120 +что +Фреймворк +HTML +на +Админ +CSS +Пакет +Сервер +Менеджер +Клиент +или +Код +Java +Слово_193 +Мобильное +Анализ +Java +C++ +Библиотека +на +C++ +Категория +Облако +на +Разработка +Настройка +Приложение +Интеллект +также +Контроль +Менеджер +на +как +JavaScript +Интеллект +Ветка +Панель +также +с +Контроль +но +Данные +Интерфейс +это +это +Java +Мобильное +CSS +от +Мобильное +Слово_446 +Панель +Игра +не +Интерфейс +Поиск +Игра +Менеджер +по +Контроль +Дизайн +Данных +Версия +HTML +но +SQL +Слово_241 +или +Сайт +Слово_422 +Контроль +Python +для +Пакет +Облако +Пакет +Фронтенд +Ошибка +Фронтенд +Python +База +не +и +Алгоритм +Искусственный +Сайт +SQL +Интерфейс +в +HTML +на +Git +и +Веб +Анализ +Менеджер +Ветка +это +Игра +C++ +Разработка +от +Сайт +Слово_223 +CSS +не +Обучение +но +Код +C++ +с +Тестирование +Мобильное +это +Функция +Интеллект +Менеджер +Система +Ошибка +как +на +Репозиторий +Оптимизация +Слово_414 +База +Ветка +также +Шифрование +Оптимизация +Пакет +Дата +для +Интерфейс +что +Разработка +Слово_248 +это +и +Контроль +Искусственный +Функция +Синтаксис +Версия +не +База +Алгоритм +Код +Нейросеть +не +Слово_430 +Фреймворк +Вход +Слово_140 +и +Безопасность +Ветка +Интеллект +Время +Репозиторий +Блог +Обучение +Время +Безопасность +в +Менеджер +SQL +Версия +Код +что +не +Шифрование +Слово_486 +с +Тестирование +Пакет +Игра +Версия +или +Пакет +и +в +но +Нейросеть +Облако +по +База +CSS +CSS +Git +но +но +Админ +но +Сайт +Сервер +Пакет +по +в +Данных +от +как +Вход +не +как +от +Пакет +Python +но +Дата +CSS +Контроль +Мобильное +Алгоритм +что +Оптимизация +также +Фреймворк +в +Java +Слово_401 +C++ +Слово_332 +или +Система +Искусственный +Админ +Слово_274 +не +Java +Сайт +это +Ветка +Интерфейс +Алгоритм +как +Категория +Полный +Дата +Интеллект +не +Слово_387 +Фреймворк +и +Алгоритм +Репозиторий +Приложение +SQL +Безопасность +Дизайн +Интерфейс +Интерфейс +Интеллект +Интерфейс +Данных +но +Приложение +также +Обучение +Облако +Оптимизация +Искусственный +не +Ветка +База +Мобильное +Пароль +Веб +как +но +для +но +Библиотека +от +Слово_256 +Менеджер +JavaScript +Слово_466 +Сортировка +в +с +на +Пакет +Фреймворк +Пакет +Синтаксис +или +Пакет +Слово_455 +Сайт +CSS +Вход +Слово_478 +по +Слово_466 +Дата +от +Клиент +также +не +HTML +как +Менеджер +Репозиторий +Сервер +для +не +Статья +Регистрация +Разработка +Java +от +Слово_483 +Интерфейс +что +SQL +в +для +для +База +от +Ветка +Поиск +не +Слово_452 +как +Версия +Тестирование +Слово_171 +Код +Python +Библиотека +CSS +по +но +но +также +Бэкенд +Нейросеть +Синтаксис +Фреймворк +Сервер +JavaScript +C++ +от +Система +Git +также +Обучение +это +Обучение +Тестирование +CSS +Вход +Функция +или +Клиент +SQL +для +Сайт +База +Слово_178 +от +Слово_455 +Контроль +Java +Игра +в +это +или +Git +Сервер +Система +Новость +Нейросеть +Искусственный +CSS +Анализ +с +Тег +Игра +Java +Обучение +Git +Безопасность +как +Обучение +для +от +Анализ +C++ +на +Разработка +Панель +для +с +это +это +в +Настройка +Система +Мобильное +Алгоритм +SQL +для +Приложение +Функция +Слово_431 +Java +Данные +с +Новость +и +Фильтр +Регистрация +и +но +Интерфейс +Игра +Java +Админ +но +Разработка +по +Система +но +Безопасность +также +Запрос +Полный +Интеллект +это +Искусственный +Git +Запрос +Интеллект +Профиль +SQL +Статья +с +Ошибка +Обучение +или +Нейросеть +Интерфейс +Репозиторий +Данные +или +Фреймворк +Функция +Менеджер +как +как +Git +Git +как +Интеллект +Веб +и +в +Фильтр +Нейросеть +Сайт +Нейросеть +Ошибка +Профиль +Ошибка +Дизайн +Алгоритм +Пакет +Ветка +Бэкенд +Поиск +SQL +Python +Функция +не +Мобильное +Искусственный +как +и +Шифрование +на +Данных +для +от +что +Искусственный +также +Интерфейс +C++ +Ошибка +Интеллект +в +Метка +но +также +Дата +также +Git +как +это +Тестирование +Контроль +Фронтенд +Логин +Нейросеть +от +C++ +HTML +Статья +Фреймворк +Клиент +Синтаксис +Облако +Пакет +это +с +Дизайн +Библиотека +Мобильное +Версия +Регистрация +Игра +Статья +Приложение +Данные +Тег +что +Слово_167 +Синтаксис +База +Настройка +Git +Функция +Менеджер +Репозиторий +Сайт +Функция +Безопасность +как +Веб +Данных +Данные +но +в +Слово_290 +Интеллект +Система +но +Искусственный +C++ +но +Время +JavaScript +HTML +в +Слово_444 +Система +C++ +Python +Безопасность +не +Функция +Git +Данных +Версия +Фреймворк +в +это +Слово_432 +Игра +и +Пакет +Репозиторий +Репозиторий +как +Интерфейс +но +или +Ошибка +Веб +по +Python +Веб +Мобильное +это +с +не +База +для +Разработка +JavaScript +Слово_478 +Приложение +это +Блог +Фильтр +Профиль +и +также +Сайт +Python +Метка +Функция +и +не +Приложение +Пакет +от +не +JavaScript +Менеджер +Тестирование +как +Git +Обучение +с +Код +Категория +Алгоритм +Разработка +Поиск +Панель +это +Слово_331 +и +в +Игра +Алгоритм +Git +но +Искусственный +Слово_185 +Облако +Мобильное +для +Функция +Пакет +Оптимизация +от +Бэкенд +также +Фреймворк +с +Новость +Игра +Сервер +на +Слово_493 +от +Код +База +не +Java +как +на +SQL +также +Игра +Менеджер +Пароль +на +Тег +Контроль +от +SQL +Поиск +Нейросеть +Дата +по +Веб +Функция +Метка +Клиент +Функция +также +Код +Пакет +и +C++ +Анализ +Клиент +CSS +Версия +Функция +HTML +от +Python +Обучение +это +Панель +Нейросеть +Приложение +Мобильное +Контроль +для +Веб +CSS +Мобильное +HTML +Версия +Искусственный +Слово_328 +HTML +как +по +Стек +Git +Пакет +Интерфейс +Стек +Статья +от +Слово_106 +Нейросеть +Анализ +Библиотека +Слово_445 +Стек +Поиск +Функция +Ветка +в +Поиск +это +Контроль +Система +но +Ошибка +Java +в +как +Код +Время +не +Блог +как +Веб +Версия +что +Python +в +Приложение +Настройка +Слово_498 +по +Облако +Категория +Веб +Пакет +Нейросеть +Пакет +это +что +Слово_169 +как +как +JavaScript +в +C++ +на +Git +и +и +HTML +Слово_460 +Java +Слово_270 +Слово_276 +Функция +JavaScript +Репозиторий +на +Искусственный +и +в +Сайт +Мобильное +Версия +также +Настройка +и +Фреймворк +с +Сайт +Слово_230 +или +Интеллект +CSS +также +Искусственный +по +как +Python +не +с +с +это +Ошибка +также +как +Python +Искусственный +Система +Разработка +Ветка +Пакет +или +Фронтенд +Игра +Система +Оптимизация +или +также +CSS +Интеллект +Слово_323 +и +Анализ +с +Админ +Шифрование +для +Мобильное +Сайт +Менеджер +Система +Алгоритм +Слово_280 +Код +Обучение +на +для +не +по +и +Интеллект +Тег +JavaScript +Разработка +Система +или +как +как +Нейросеть +как +или +Фреймворк +но +HTML +Тестирование +Облако +Нейросеть +Новость +в +Тег +Репозиторий +Слово_326 +как +Нейросеть +Данных +Регистрация +как +Веб +Мобильное +Слово_341 +Версия +Тестирование +но +Интерфейс +от +База +Ошибка +по +для +Данные +и +как +Обучение +Блог +по +HTML +Слово_238 +Менеджер +Контроль +Анализ +Время +что +Git +База +Веб +Версия +по +но +Слово_170 +Git +Слово_192 +что +по +Метка +в +Блог +Слово_351 +не +от +Тестирование +Контроль +Функция +Код +с +не +не +Дизайн +HTML +в +Стек +Система +HTML +Слово_379 +на +и +Интеллект +Запрос +это +Тег +Оптимизация +Статья +что +Приложение +Клиент +Игра +Ветка +или +Слово_121 +Анализ +с +на +также +Пользователь +Слово_293 +что +в +Дизайн +Сайт +и +что +SQL +Нейросеть +Контроль +Искусственный +это +Контроль +Слово_285 +Категория +Искусственный +Шифрование +как +Библиотека +это +как +но +Фреймворк +не +и +также +Слово_368 +Безопасность +или +Пакет +Интеллект +HTML +также +в +не +JavaScript +как +по +Приложение +Обучение +не +Менеджер +это +Python +Профиль +Репозиторий +Категория +Контроль +что +Категория +Пользователь +Синтаксис +Python +в +Версия +Нейросеть +и +от +Поиск +HTML +для +Интерфейс +Код +Слово_418 +Дизайн +Слово_441 +HTML +HTML +для +Система +это +Фильтр +Мобильное +Код +Метка +Код +JavaScript +Библиотека +Python +это +Слово_262 +Система +Вход +для +от +Пакет +Искусственный +Git +также +также +Приложение +SQL +База +что +Ошибка +Игра +и +Функция +как +C++ +Ошибка +HTML +Обучение +также +для +Сайт +но +JavaScript +но +Фильтр +но +Метка +или +Нейросеть +Приложение +Клиент +Поиск +Настройка +как +для +Приложение +Java +Слово_328 +Версия +также +Данные +это +Искусственный +Python +не +JavaScript +Версия +Версия +Данных +База +и +по +в +Сайт +Сайт +или +но +в +Клиент +Полный +Шифрование +в +Поиск +SQL +Анализ +Слово_452 +Python +и +Слово_322 +Веб +Дизайн +Приложение +Клиент +Новость +Библиотека +Мобильное +как +Слово_486 +и +Мобильное +Статья +Нейросеть +Тестирование +Функция +Слово_214 +CSS +и +и +как +Java +или +по +не +SQL +Интерфейс +по +Код +Искусственный +Дата +Дата +Библиотека +Дизайн +Git +по +Тестирование +в +Ветка +Сортировка +Админ +Интерфейс +Данные +что +или +CSS +на +Фронтенд +Дизайн +Мобильное +и +Настройка +Слово_160 +Игра +Игра +Git +Запрос +Интерфейс +по +Дата +в +Функция +SQL +Анализ +по +Обучение +на +на +Разработка +для +Данные +с +Приложение +для +Менеджер +Обучение +Веб +Данных +Пакет +Менеджер +Система +Менеджер +Пароль +Мобильное +в +и +также +Время +на +Репозиторий +Игра +HTML +Настройка +Фреймворк +Java +CSS +Менеджер +по +с +Репозиторий +Полный +Система +по +Клиент +как +Искусственный +от +как +Python +Статья +Бэкенд +Искусственный +Слово_449 +и +Функция +и +с +или +Оптимизация +Java +от +CSS +или +Панель +База +Настройка +это +Разработка +Система +от +Java +Тестирование +HTML +База +как +также +HTML +это +как +Интерфейс +C++ +Сервер +Приложение +Версия +CSS +но +Данные +для +Сервер +Вход +Функция +и +и +Веб +также +это +Обучение +Python +Дизайн +Python +Веб +Настройка +также +Мобильное +Интеллект +на +по +Java +или +также +Клиент +Java +Настройка +Дизайн +Разработка +Интерфейс +Синтаксис +Алгоритм +CSS +также +и +SQL +JavaScript +SQL +Python +Вход +Фреймворк +не +для +CSS +Слово_399 +Вход +База +Нейросеть +Игра +Интеллект +SQL +SQL +как +Фреймворк +Контроль +в +с +но +Админ +Вход +Версия +Библиотека +Бэкенд +Репозиторий +что +HTML +Python +в +на +Анализ +Слово_439 +с +Анализ +Репозиторий +не +Сервер +не +что +Версия +CSS +Полный +Мобильное +SQL +Сервер +Пароль +или +но +на +в +Панель +что +Приложение +не +SQL +но +Логин +Веб +Нейросеть +для +для +Сервер +Тестирование +Дизайн +Обучение +в +в +Менеджер +Слово_277 +для +HTML +Логин +Git +не +но +не +Обучение +Фреймворк +или +Вход +от +Интеллект +Новость +Слово_107 +Блог +Пользователь +Тестирование +Репозиторий +на +База +как +что +также +не +по +Дизайн +Git +Настройка +Сайт +Git +Python +от +с +Веб +Облако +не +Клиент +с +Ошибка +Запрос +от +Разработка +и +Библиотека +с +от +Веб +по +Интерфейс +Клиент +Данные +Стек +от +Код +Ошибка +Ошибка +Анализ +Панель +Ветка +Сервер +Настройка +Шифрование +или +Данных +Бэкенд +Пакет +Python +База +Шифрование +Мобильное +в +Блог +что +как +по +Нейросеть +или +и +от +Разработка +Время +Данные +Полный +Веб +Ветка +Данные +но +Библиотека +Регистрация +Версия +Игра +Искусственный +Тестирование +но +Java +Панель +Фреймворк +Алгоритм +Обучение +Ветка +Статья +JavaScript +Репозиторий +Версия +как +для +Веб +Python +HTML +для +Слово_453 +Анализ +Нейросеть +это +для +Слово_369 +Ошибка +в +на +Новость +но +JavaScript +Контроль +Вход +Поиск +это +Тестирование +Искусственный +на +Репозиторий +что +по +Веб +Слово_257 +Панель +Приложение +JavaScript +Интерфейс +Мобильное +База +Система +Интеллект +по +Клиент +Категория +также +Поиск +Слово_231 +на +Java +Анализ +но +Слово_111 +Репозиторий +Пакет +по +Ветка +Разработка +для +Время +как +от +что +не +не +Python +Категория +также +Фреймворк +но +Искусственный +Клиент +Поиск +Код +Версия +не +Тег +не +Приложение +Ветка +Алгоритм +Разработка +Слово_179 +также +Система +Тег +с +Тестирование +это +как +от +Менеджер +Сервер +по +и +или +Функция +C++ +Настройка +Профиль +Слово_338 +но +Слово_378 +Приложение +Слово_338 +Слово_478 +Разработка +Анализ +Искусственный +Пакет +также +Фреймворк +как +по +по +CSS +HTML +Ошибка +с +JavaScript +Интерфейс +Данные +или +Слово_202 +Настройка +и +на +или +Оптимизация +Клиент +Python +но +Ошибка +также +SQL +от +Данные +от +SQL +Дата +Git +Пакет +Дизайн +Полный +Данные +JavaScript +на +или +Контроль +Время +но +Библиотека +Разработка +Блог +как +не +в +по +Игра +JavaScript +и +в +Слово_432 +Слово_313 +Данные +в +не +для +Python +для +что +с +Java +но +Интеллект +C++ +Сервер +не +Облако +Настройка +Интерфейс +Слово_131 +это +Синтаксис +Обучение +как +Тег +Регистрация +по +Дизайн +Облако +с +это +Слово_279 +Анализ +Пользователь +с +Облако +Дизайн +Интерфейс +Дата +с +Бэкенд +Слово_197 +HTML +Статья +Библиотека +не +Код +по +Сайт +CSS +Версия +на +с +или +Данные +как +Мобильное +Python