diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index aac0deb..77a9ba3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,30 +2,7 @@
on: [push, pull_request]
jobs:
- build-ubuntu:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-dotnet@v4
- with:
- dotnet-version: '9.x'
-
- - name: Build
- run: |
- for f in $(find . -name "*.sln"); do
- if [[ "$f" != *"CalculatorOnForms2"* ]]; then
- dotnet build "$f"
- fi
- done
-
- - name: Run tests
- run: |
- for f in $(find . -name "*.sln"); do
- if [[ "$f" != *"CalculatorOnForms2"* ]]; then
- dotnet test "$f"
- fi
- done
-
+
build-windows:
runs-on: windows-latest
steps:
diff --git a/HW3/CalculatorCore.Test/CalculatorCore.Test.csproj b/HW3/CalculatorCore.Test/CalculatorCore.Test.csproj
new file mode 100644
index 0000000..96e3dbb
--- /dev/null
+++ b/HW3/CalculatorCore.Test/CalculatorCore.Test.csproj
@@ -0,0 +1,39 @@
+
+
+
+ net8.0-windows
+ enable
+ enable
+ true
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
diff --git a/HW3/CalculatorCore.Test/CalculatorTest.cs b/HW3/CalculatorCore.Test/CalculatorTest.cs
new file mode 100644
index 0000000..5673e71
--- /dev/null
+++ b/HW3/CalculatorCore.Test/CalculatorTest.cs
@@ -0,0 +1,203 @@
+//
+// Copyright (c) khusainovilas. All rights reserved.
+//
+
+namespace CalculatorCore.Test;
+
+using NUnit.Framework;
+
+///
+/// A set of unit tests to verify the business logic of the class.
+/// These tests check arithmetic operations, error handling, and helper methods.
+///
+public class CalculatorTest
+{
+ private CalculatorLogic calculator;
+
+ ///
+ /// Runs before each test to create a fresh calculator instance.
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ this.calculator = new CalculatorLogic();
+ }
+
+ ///
+ /// Tests that digits are appended correctly to the display.
+ ///
+ [Test]
+ public void CalculatorLogic_AppendDigit_AppendsDigitsCorrectly()
+ {
+ this.calculator.AppendDigit("1");
+ this.calculator.AppendDigit("2");
+
+ Assert.That(this.calculator.Display, Is.EqualTo("12"));
+ }
+
+ ///
+ /// Tests that invalid characters (non-numeric and not a dot) are ignored.
+ ///
+ [Test]
+ public void CalculatorLogic_AppendDigit_InvalidCharacter_IsIgnored()
+ {
+ this.calculator.AppendDigit("a");
+
+ Assert.That(this.calculator.Display, Is.EqualTo("0"));
+ }
+
+ ///
+ /// Tests that only one decimal dot can be added.
+ ///
+ [Test]
+ public void CalculatorLogic_AppendDigit_DoubleDot_IsIgnored()
+ {
+ this.calculator.AppendDigit("1");
+ this.calculator.AppendDigit(",");
+ this.calculator.AppendDigit(",");
+ this.calculator.AppendDigit("5");
+
+ Assert.That(this.calculator.Display, Is.EqualTo("1,5"));
+ }
+
+ ///
+ /// Tests that addition returns the correct result.
+ ///
+ [Test]
+ public void CalculatorLogic_SetOperator_Addition_ReturnsCorrectResult()
+ {
+ this.calculator.AppendDigit("2");
+ this.calculator.SetOperator("+");
+ this.calculator.AppendDigit("3");
+ this.calculator.Calculate();
+
+ Assert.That(this.calculator.Display, Is.EqualTo("5"));
+ }
+
+ ///
+ /// Tests that subtraction returns the correct result.
+ ///
+ [Test]
+ public void CalculatorLogic_SetOperator_Subtraction_ReturnsCorrectResult()
+ {
+ this.calculator.AppendDigit("9");
+ this.calculator.SetOperator("-");
+ this.calculator.AppendDigit("4");
+ this.calculator.Calculate();
+
+ Assert.That(this.calculator.Display, Is.EqualTo("5"));
+ }
+
+ ///
+ /// Tests that multiplication returns the correct result.
+ ///
+ [Test]
+ public void CalculatorLogic_SetOperator_Multiplication_ReturnsCorrectResult()
+ {
+ this.calculator.AppendDigit("6");
+ this.calculator.SetOperator("*");
+ this.calculator.AppendDigit("7");
+ this.calculator.Calculate();
+
+ Assert.That(this.calculator.Display, Is.EqualTo("42"));
+ }
+
+ ///
+ /// Tests that division returns the correct result.
+ ///
+ [Test]
+ public void CalculatorLogic_SetOperator_Division_ReturnsCorrectResult()
+ {
+ this.calculator.AppendDigit("8");
+ this.calculator.SetOperator("/");
+ this.calculator.AppendDigit("2");
+ this.calculator.Calculate();
+
+ Assert.That(this.calculator.Display, Is.EqualTo("4"));
+ }
+
+ ///
+ /// Tests that division by zero results in an error message.
+ ///
+ [Test]
+ public void CalculatorLogic_SetOperator_DivisionByZero_ShowsError()
+ {
+ this.calculator.AppendDigit("8");
+ this.calculator.SetOperator("/");
+ this.calculator.AppendDigit("0");
+ this.calculator.Calculate();
+
+ Assert.That(this.calculator.Display, Is.EqualTo("Error"));
+ }
+
+ ///
+ /// Tests that the Clear method resets the calculator state completely.
+ ///
+ [Test]
+ public void CalculatorLogic_Clear_ResetsAllState()
+ {
+ this.calculator.AppendDigit("9");
+ this.calculator.SetOperator("+");
+ this.calculator.AppendDigit("1");
+ this.calculator.Clear();
+
+ Assert.That(this.calculator.Display, Is.EqualTo("0"));
+ }
+
+ ///
+ /// Tests that ClearEnter only clears the current input, not the stored result.
+ ///
+ [Test]
+ public void CalculatorLogic_ClearEnter_ClearsOnlyCurrentInput()
+ {
+ this.calculator.AppendDigit("9");
+ this.calculator.SetOperator("+");
+ this.calculator.AppendDigit("3");
+ this.calculator.ClearEnter();
+
+ Assert.That(this.calculator.Display, Is.EqualTo("9"));
+ }
+
+ ///
+ /// Tests that Backspace removes the last entered digit.
+ ///
+ [Test]
+ public void CalculatorLogic_Backspace_RemovesLastDigit()
+ {
+ this.calculator.AppendDigit("1");
+ this.calculator.AppendDigit("2");
+ this.calculator.AppendDigit("3");
+ this.calculator.Backspace();
+
+ Assert.That(this.calculator.Display, Is.EqualTo("12"));
+ }
+
+ ///
+ /// Tests that Backspace on empty input keeps the display as "0".
+ ///
+ [Test]
+ public void CalculatorLogic_Backspace_OnEmptyInput_KeepsZero()
+ {
+ this.calculator.Backspace();
+
+ Assert.That(this.calculator.Display, Is.EqualTo("0"));
+ }
+
+ ///
+ /// Tests that sequential operations use the previous result as the first operand.
+ ///
+ [Test]
+ public void CalculatorLogic_Calculate_SequentialOperations_UsesPreviousResult()
+ {
+ this.calculator.AppendDigit("5");
+ this.calculator.SetOperator("+");
+ this.calculator.AppendDigit("5");
+ this.calculator.Calculate();
+
+ this.calculator.SetOperator("*");
+ this.calculator.AppendDigit("2");
+ this.calculator.Calculate();
+
+ Assert.That(this.calculator.Display, Is.EqualTo("20"));
+ }
+}
diff --git a/HW3/CalculatorCore.Test/stylecop.json b/HW3/CalculatorCore.Test/stylecop.json
new file mode 100644
index 0000000..76c8e76
--- /dev/null
+++ b/HW3/CalculatorCore.Test/stylecop.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
+ "settings": {
+ "documentationRules": {
+ "companyName": "khusainovilas",
+ "copyrightText": "Copyright (c) {companyName}. All rights reserved."
+ }
+ }
+}
\ No newline at end of file
diff --git a/HW3/CalculatorCore/CalculatorCore.csproj b/HW3/CalculatorCore/CalculatorCore.csproj
new file mode 100644
index 0000000..40abd96
--- /dev/null
+++ b/HW3/CalculatorCore/CalculatorCore.csproj
@@ -0,0 +1,23 @@
+
+
+
+ WinExe
+ net8.0-windows
+ true
+ enable
+ enable
+ true
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
diff --git a/HW3/CalculatorCore/CalculatorLogic.cs b/HW3/CalculatorCore/CalculatorLogic.cs
new file mode 100644
index 0000000..88fa6d3
--- /dev/null
+++ b/HW3/CalculatorCore/CalculatorLogic.cs
@@ -0,0 +1,292 @@
+//
+// Copyright (c) khusainovilas. All rights reserved.
+//
+
+namespace CalculatorCore;
+
+using System.ComponentModel;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+
+///
+/// Handles the calculator's core logic: input processing, arithmetic operations, and display updates.
+///
+public class CalculatorLogic : INotifyPropertyChanged
+{
+ private double? currentValue;
+ private string? pendingOperator;
+ private string? display = "0";
+ private bool isNewInput = true;
+ private string inputBuffer = string.Empty;
+ private bool hasError;
+
+ ///
+ public event PropertyChangedEventHandler? PropertyChanged;
+
+ ///
+ /// Gets the value shown on the calculator screen.
+ /// Automatically updates the UI when changed.
+ ///
+ public string? Display
+ {
+ get => this.display;
+ private set
+ {
+ if (this.display == value)
+ {
+ return;
+ }
+
+ this.display = value;
+ this.OnPropertyChanged();
+ }
+ }
+
+ ///
+ /// Appends a digit or a decimal point to the current number.
+ ///
+ /// The digit (0–9) or decimal point (".").
+ public void AppendDigit(string? digit)
+ {
+ if (this.hasError)
+ {
+ this.Clear();
+ }
+
+ if (digit is "," or ".")
+ {
+ digit = ",";
+ }
+
+ if (digit != "," && !char.IsDigit(digit ?? string.Empty, 0))
+ {
+ return;
+ }
+
+ if (this.isNewInput)
+ {
+ this.inputBuffer = string.Empty;
+ this.isNewInput = false;
+ }
+
+ switch (digit)
+ {
+ case "," when this.inputBuffer.Contains(','):
+ return;
+ case "," when string.IsNullOrEmpty(this.inputBuffer):
+ this.inputBuffer = "0,";
+ break;
+ default:
+ this.inputBuffer += digit;
+ break;
+ }
+
+ this.Display = this.inputBuffer.Length > 0 ? this.inputBuffer : "0";
+ }
+
+ ///
+ /// Sets the operator (+, -, *, /) and, if possible, performs the intermediate calculation.
+ ///
+ /// The operator symbol.
+ public void SetOperator(string @operator)
+ {
+ if (this.hasError)
+ {
+ this.Clear();
+ }
+
+ if (@operator != "+" && @operator != "-" && @operator != "*" && @operator != "/")
+ {
+ return;
+ }
+
+ if (!string.IsNullOrEmpty(this.inputBuffer))
+ {
+ if (!TryParseInput(this.inputBuffer, out var number))
+ {
+ this.DisplayError();
+ return;
+ }
+
+ if (this.currentValue == null)
+ {
+ this.currentValue = number;
+ }
+ else if (this.pendingOperator != null)
+ {
+ if (!TryCalculate(this.currentValue.Value, number, this.pendingOperator, out var result))
+ {
+ this.DisplayError();
+ return;
+ }
+
+ this.currentValue = result;
+ this.Display = ConvertToDisplay(result);
+ }
+
+ this.inputBuffer = string.Empty;
+ this.isNewInput = true;
+ }
+
+ this.pendingOperator = @operator;
+ this.Display = this.currentValue != null ? ConvertToDisplay(this.currentValue.Value) : "0";
+ }
+
+ ///
+ /// Performs the final calculation and updates the display.
+ ///
+ public void Calculate()
+ {
+ if (this.hasError)
+ {
+ return;
+ }
+
+ if (this.pendingOperator == null || string.IsNullOrEmpty(this.inputBuffer))
+ {
+ return;
+ }
+
+ if (this.inputBuffer.EndsWith(','))
+ {
+ this.inputBuffer = this.inputBuffer[..^1];
+ }
+
+ if (!TryParseInput(this.inputBuffer, out var secondNumber))
+ {
+ this.DisplayError();
+ return;
+ }
+
+ if (this.currentValue == null)
+ {
+ this.currentValue = secondNumber;
+ this.Display = ConvertToDisplay(secondNumber);
+ this.inputBuffer = string.Empty;
+ this.isNewInput = true;
+ this.pendingOperator = null;
+ return;
+ }
+
+ if (!TryCalculate(this.currentValue.Value, secondNumber, this.pendingOperator, out var result))
+ {
+ this.DisplayError();
+ return;
+ }
+
+ this.currentValue = result;
+ this.Display = ConvertToDisplay(result);
+
+ this.inputBuffer = string.Empty;
+ this.isNewInput = true;
+ this.pendingOperator = null;
+ }
+
+ ///
+ /// Completely clears the calculator state.
+ ///
+ public void Clear()
+ {
+ this.currentValue = null;
+ this.pendingOperator = null;
+ this.inputBuffer = string.Empty;
+ this.isNewInput = true;
+ this.hasError = false;
+ this.Display = "0";
+ }
+
+ ///
+ /// Clears the current entry while keeping the stored result and operator.
+ ///
+ public void ClearEnter()
+ {
+ if (this.hasError)
+ {
+ this.Clear();
+ return;
+ }
+
+ if (this.isNewInput && string.IsNullOrEmpty(this.inputBuffer))
+ {
+ this.currentValue = null;
+ this.pendingOperator = null;
+ this.Display = "0";
+ return;
+ }
+
+ this.inputBuffer = string.Empty;
+ this.isNewInput = true;
+ this.Display = this.currentValue != null ? ConvertToDisplay(this.currentValue.Value) : "0";
+ }
+
+ ///
+ /// Deletes the last entered digit.
+ ///
+ public void Backspace()
+ {
+ if (this.hasError)
+ {
+ this.Clear();
+ return;
+ }
+
+ if (this.isNewInput && string.IsNullOrEmpty(this.inputBuffer))
+ {
+ this.inputBuffer = this.Display ?? "0";
+ this.isNewInput = false;
+ this.currentValue = null;
+ this.pendingOperator = null;
+ }
+
+ if (this.inputBuffer.Length <= 0)
+ {
+ this.Display = "0";
+ return;
+ }
+
+ this.inputBuffer = this.inputBuffer[..^1];
+ this.Display = this.inputBuffer.Length > 0 ? this.inputBuffer : "0";
+ }
+
+ private static bool TryCalculate(double first, double second, string @operator, out double result)
+ {
+ try
+ {
+ result = @operator switch
+ {
+ "+" => first + second,
+ "-" => first - second,
+ "*" => first * second,
+ "/" => second != 0 ? first / second : throw new DivideByZeroException(),
+ _ => throw new InvalidOperationException("Unknown operator"),
+ };
+ return true;
+ }
+ catch
+ {
+ result = 0;
+ return false;
+ }
+ }
+
+ private static bool TryParseInput(string input, out double number)
+ {
+ return double.TryParse(input, NumberStyles.Float, new CultureInfo("ru-RU"), out number);
+ }
+
+ private static string ConvertToDisplay(double number)
+ {
+ return number.ToString(new CultureInfo("ru-RU"));
+ }
+
+ private void DisplayError()
+ {
+ this.Display = "Error";
+ this.hasError = true;
+ }
+
+ private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
+ {
+ this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+}
diff --git a/HW3/CalculatorCore/MainForm.cs b/HW3/CalculatorCore/MainForm.cs
new file mode 100644
index 0000000..b8da8fc
--- /dev/null
+++ b/HW3/CalculatorCore/MainForm.cs
@@ -0,0 +1,150 @@
+//
+// Copyright (c) khusainovilas. All rights reserved.
+//
+
+namespace CalculatorCore;
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Drawing;
+using System.Windows.Forms;
+
+///
+/// The main WinForms form calculator.
+///
+public class MainForm : Form
+{
+ private readonly CalculatorLogic calculatorLogic;
+ private readonly TextBox displayTextBox;
+
+ ///
+ /// Initializes a new instance of the class.
+ /// Form constructor, initializes the UI and data binding.
+ ///
+ public MainForm()
+ {
+ this.calculatorLogic = new CalculatorLogic();
+ this.Size = new Size(300, 400);
+ this.Text = "CalculatorApp";
+ this.FormBorderStyle = FormBorderStyle.FixedSingle;
+ this.MaximizeBox = false;
+
+ this.displayTextBox = new TextBox
+ {
+ Location = new Point(10, 10),
+ Size = new Size(260, 40),
+ Font = new Font("Arial", 20),
+ TextAlign = HorizontalAlignment.Right,
+ ReadOnly = true,
+ };
+ this.Controls.Add(this.displayTextBox);
+
+ this.displayTextBox.DataBindings.Add(nameof(this.Text), this.calculatorLogic, "Display", false, DataSourceUpdateMode.OnPropertyChanged);
+
+ var buttonPanel = new TableLayoutPanel
+ {
+ Location = new Point(10, 60),
+ Size = new Size(260, 300),
+ RowCount = 5,
+ ColumnCount = 4,
+ };
+ buttonPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 20));
+ buttonPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 20));
+ buttonPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 20));
+ buttonPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 20));
+ buttonPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 20));
+ buttonPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25));
+ buttonPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25));
+ buttonPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25));
+ buttonPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25));
+ this.Controls.Add(buttonPanel);
+
+ this.CreateButton(buttonPanel, "7", 0, 0);
+ this.CreateButton(buttonPanel, "8", 0, 1);
+ this.CreateButton(buttonPanel, "9", 0, 2);
+ this.CreateButton(buttonPanel, "/", 0, 3);
+
+ this.CreateButton(buttonPanel, "4", 1, 0);
+ this.CreateButton(buttonPanel, "5", 1, 1);
+ this.CreateButton(buttonPanel, "6", 1, 2);
+ this.CreateButton(buttonPanel, "*", 1, 3);
+
+ this.CreateButton(buttonPanel, "1", 2, 0);
+ this.CreateButton(buttonPanel, "2", 2, 1);
+ this.CreateButton(buttonPanel, "3", 2, 2);
+ this.CreateButton(buttonPanel, "-", 2, 3);
+
+ this.CreateButton(buttonPanel, "0", 3, 0);
+ this.CreateButton(buttonPanel, ".", 3, 1);
+ this.CreateButton(buttonPanel, "=", 3, 2);
+ this.CreateButton(buttonPanel, "+", 3, 3);
+
+ this.CreateButton(buttonPanel, "C", 4, 0);
+ this.CreateButton(buttonPanel, "CE", 4, 1);
+ this.CreateButton(buttonPanel, "←", 4, 2);
+ }
+
+ ///
+ [AllowNull]
+ public sealed override string Text
+ {
+ get => base.Text;
+ set => base.Text = value;
+ }
+
+ ///
+ /// Creates a button and adds it to the grid, with a click handler.
+ ///
+ /// Grid for the button.
+ /// Button content.
+ /// Row in the grid.
+ /// Column in the grid.
+ private void CreateButton(TableLayoutPanel panel, string content, int row, int column)
+ {
+ var button = new Button
+ {
+ Text = content,
+ Font = new Font("Arial", 14),
+ Dock = DockStyle.Fill,
+ };
+ button.Click += this.Button_Click!;
+ panel.Controls.Add(button, column, row);
+ }
+
+ ///
+ /// Handles a button click by calling logic methods.
+ ///
+ /// Button.
+ /// Event arguments.
+ private void Button_Click(object sender, EventArgs e)
+ {
+ var button = (Button)sender;
+ var buttonContent = button.Text;
+
+ if (char.IsDigit(buttonContent, 0) || buttonContent == ".")
+ {
+ this.calculatorLogic.AppendDigit(buttonContent);
+ }
+ else
+ {
+ switch (buttonContent)
+ {
+ case "+" or "-" or "*" or "/":
+ this.calculatorLogic.SetOperator(buttonContent);
+ break;
+ case "=":
+ this.calculatorLogic.Calculate();
+ break;
+ case "C":
+ this.calculatorLogic.Clear();
+ break;
+ case "CE":
+ this.calculatorLogic.ClearEnter();
+ break;
+ case "←":
+ this.calculatorLogic.Backspace();
+ break;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/HW3/CalculatorCore/Program.cs b/HW3/CalculatorCore/Program.cs
new file mode 100644
index 0000000..02ee532
--- /dev/null
+++ b/HW3/CalculatorCore/Program.cs
@@ -0,0 +1,9 @@
+//
+// Copyright (c) khusainovilas. All rights reserved.
+//
+
+using CalculatorCore;
+
+Application.EnableVisualStyles();
+Application.SetCompatibleTextRenderingDefault(false);
+Application.Run(new MainForm());
\ No newline at end of file
diff --git a/HW3/CalculatorCore/stylecop.json b/HW3/CalculatorCore/stylecop.json
new file mode 100644
index 0000000..76c8e76
--- /dev/null
+++ b/HW3/CalculatorCore/stylecop.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
+ "settings": {
+ "documentationRules": {
+ "companyName": "khusainovilas",
+ "copyrightText": "Copyright (c) {companyName}. All rights reserved."
+ }
+ }
+}
\ No newline at end of file
diff --git a/HW3/HW3.sln b/HW3/HW3.sln
new file mode 100644
index 0000000..8c20cc0
--- /dev/null
+++ b/HW3/HW3.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CalculatorCore", "CalculatorCore\CalculatorCore.csproj", "{5D070A5B-FA66-416C-B482-A5396D4A04C1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CalculatorCore.Test", "CalculatorCore.Test\CalculatorCore.Test.csproj", "{A7EE239C-A0EC-48F7-92F1-C6B5DB9973E5}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {5D070A5B-FA66-416C-B482-A5396D4A04C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5D070A5B-FA66-416C-B482-A5396D4A04C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5D070A5B-FA66-416C-B482-A5396D4A04C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5D070A5B-FA66-416C-B482-A5396D4A04C1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A7EE239C-A0EC-48F7-92F1-C6B5DB9973E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A7EE239C-A0EC-48F7-92F1-C6B5DB9973E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A7EE239C-A0EC-48F7-92F1-C6B5DB9973E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A7EE239C-A0EC-48F7-92F1-C6B5DB9973E5}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal