diff --git a/TheBank/BankBusinessLogic/BankBusinessLogic.csproj b/TheBank/BankBusinessLogic/BankBusinessLogic.csproj
index 83b7798..1060896 100644
--- a/TheBank/BankBusinessLogic/BankBusinessLogic.csproj
+++ b/TheBank/BankBusinessLogic/BankBusinessLogic.csproj
@@ -14,4 +14,9 @@
+
+
+
+
+
diff --git a/TheBank/BankContracts/AdapterContracts/IClerkAdapter.cs b/TheBank/BankContracts/AdapterContracts/IClerkAdapter.cs
new file mode 100644
index 0000000..265696e
--- /dev/null
+++ b/TheBank/BankContracts/AdapterContracts/IClerkAdapter.cs
@@ -0,0 +1,18 @@
+using BankContracts.AdapterContracts.OperationResponses;
+using BankContracts.BindingModels;
+
+namespace BankContracts.AdapterContracts;
+
+///
+/// контракт адаптера для клерка
+///
+public interface IClerkAdapter
+{
+ ClerkOperationResponse GetList();
+
+ ClerkOperationResponse GetElement(string data);
+
+ ClerkOperationResponse RegisterClerk(ClerkBindingModel clerkDataModel);
+
+ ClerkOperationResponse ChangeClerkInfo(ClerkBindingModel clerkDataModel);
+}
diff --git a/TheBank/BankContracts/AdapterContracts/OperationResponses/ClerkOperationResponse.cs b/TheBank/BankContracts/AdapterContracts/OperationResponses/ClerkOperationResponse.cs
new file mode 100644
index 0000000..223b6ad
--- /dev/null
+++ b/TheBank/BankContracts/AdapterContracts/OperationResponses/ClerkOperationResponse.cs
@@ -0,0 +1,24 @@
+using BankContracts.Infrastructure;
+using BankContracts.ViewModels;
+
+namespace BankContracts.AdapterContracts.OperationResponses;
+
+public class ClerkOperationResponse : OperationResponse
+{
+ public static ClerkOperationResponse OK(List data) =>
+ OK>(data);
+
+ public static ClerkOperationResponse OK(ClerkViewModel data) =>
+ OK(data);
+
+ public static ClerkOperationResponse NoContent() => NoContent();
+
+ public static ClerkOperationResponse NotFound(string message) =>
+ NotFound(message);
+
+ public static ClerkOperationResponse BadRequest(string message) =>
+ BadRequest(message);
+
+ public static ClerkOperationResponse InternalServerError(string message) =>
+ InternalServerError(message);
+}
diff --git a/TheBank/BankContracts/BankContracts.csproj b/TheBank/BankContracts/BankContracts.csproj
index 125f4c9..1728919 100644
--- a/TheBank/BankContracts/BankContracts.csproj
+++ b/TheBank/BankContracts/BankContracts.csproj
@@ -6,4 +6,10 @@
enable
+
+
+
+
+
+
diff --git a/TheBank/BankContracts/BindingModels/ClerkBindingModel.cs b/TheBank/BankContracts/BindingModels/ClerkBindingModel.cs
new file mode 100644
index 0000000..7bdd24e
--- /dev/null
+++ b/TheBank/BankContracts/BindingModels/ClerkBindingModel.cs
@@ -0,0 +1,23 @@
+namespace BankContracts.BindingModels;
+
+///
+/// модель ответа от клиента для клерка
+///
+public class ClerkBindingModel
+{
+ public string? Id { get; set; }
+
+ public string? Name { get; set; }
+
+ public string? Surname { get; set; }
+
+ public string? MiddleName { get; set; }
+
+ public string? Login { get; set; }
+
+ public string? Password { get; set; }
+
+ public string? Email { get; set; }
+
+ public string? PhoneNumber { get; set; }
+}
diff --git a/TheBank/BankContracts/Infrastructure/OperationResponse.cs b/TheBank/BankContracts/Infrastructure/OperationResponse.cs
new file mode 100644
index 0000000..d3eafe6
--- /dev/null
+++ b/TheBank/BankContracts/Infrastructure/OperationResponse.cs
@@ -0,0 +1,49 @@
+using System.Net;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+namespace BankContracts.Infrastructure;
+
+///
+/// класс для http ответов
+///
+public class OperationResponse
+{
+ protected HttpStatusCode StatusCode { get; set; }
+
+ protected object? Result { get; set; }
+
+ public IActionResult GetResponse(HttpRequest request, HttpResponse response)
+ {
+ ArgumentNullException.ThrowIfNull(request);
+ ArgumentNullException.ThrowIfNull(response);
+
+ response.StatusCode = (int)StatusCode;
+
+ if (Result is null)
+ {
+ return new StatusCodeResult((int)StatusCode);
+ }
+
+ return new ObjectResult(Result);
+ }
+
+ protected static TResult OK(TData data)
+ where TResult : OperationResponse, new() =>
+ new() { StatusCode = HttpStatusCode.OK, Result = data };
+
+ protected static TResult NoContent()
+ where TResult : OperationResponse, new() => new() { StatusCode = HttpStatusCode.NoContent };
+
+ protected static TResult BadRequest(string? errorMessage = null)
+ where TResult : OperationResponse, new() =>
+ new() { StatusCode = HttpStatusCode.BadRequest, Result = errorMessage };
+
+ protected static TResult NotFound(string? errorMessage = null)
+ where TResult : OperationResponse, new() =>
+ new() { StatusCode = HttpStatusCode.NotFound, Result = errorMessage };
+
+ protected static TResult InternalServerError(string? errorMessage = null)
+ where TResult : OperationResponse, new() =>
+ new() { StatusCode = HttpStatusCode.InternalServerError, Result = errorMessage };
+}
diff --git a/TheBank/BankContracts/ViewModels/ClerkViewModel.cs b/TheBank/BankContracts/ViewModels/ClerkViewModel.cs
new file mode 100644
index 0000000..cc2ab42
--- /dev/null
+++ b/TheBank/BankContracts/ViewModels/ClerkViewModel.cs
@@ -0,0 +1,23 @@
+namespace BankContracts.ViewModels;
+
+///
+/// модель представления для клерка
+///
+public class ClerkViewModel
+{
+ public required string Id { get; set; }
+
+ public required string Name { get; set; }
+
+ public required string Surname { get; set; }
+
+ public required string MiddleName { get; set; }
+
+ public required string Login { get; set; }
+
+ public required string Password { get; set; }
+
+ public required string Email { get; set; }
+
+ public required string PhoneNumber { get; set; }
+}
diff --git a/TheBank/BankDatabase/BankDatabase.csproj b/TheBank/BankDatabase/BankDatabase.csproj
index c4e8569..909458d 100644
--- a/TheBank/BankDatabase/BankDatabase.csproj
+++ b/TheBank/BankDatabase/BankDatabase.csproj
@@ -20,4 +20,8 @@
+
+
+
+
diff --git a/TheBank/BankWebApi/Adapters/ClerkAdapter.cs b/TheBank/BankWebApi/Adapters/ClerkAdapter.cs
new file mode 100644
index 0000000..889d349
--- /dev/null
+++ b/TheBank/BankWebApi/Adapters/ClerkAdapter.cs
@@ -0,0 +1,173 @@
+using AutoMapper;
+using BankContracts.AdapterContracts;
+using BankContracts.AdapterContracts.OperationResponses;
+using BankContracts.BindingModels;
+using BankContracts.BusinessLogicContracts;
+using BankContracts.DataModels;
+using BankContracts.Exceptions;
+using BankContracts.ViewModels;
+
+namespace BankWebApi.Adapters;
+
+public class ClerkAdapter : IClerkAdapter
+{
+ private readonly IClerkBusinessLogicContract _clerkBusinessLogicContract;
+
+ private readonly ILogger _logger;
+
+ private readonly Mapper _mapper;
+
+ public ClerkAdapter(IClerkBusinessLogicContract clerkBusinessLogicContract, ILogger logger)
+ {
+ _clerkBusinessLogicContract = clerkBusinessLogicContract;
+ _logger = logger;
+ var config = new MapperConfiguration(cfg =>
+ {
+ cfg.CreateMap();
+ cfg.CreateMap();
+ });
+ _mapper = new Mapper(config);
+ }
+
+ public ClerkOperationResponse GetList()
+ {
+ try
+ {
+ return ClerkOperationResponse.OK(
+ [
+ .. _clerkBusinessLogicContract
+ .GetAllClerks()
+ .Select(x => _mapper.Map(x)),
+ ]
+ );
+ }
+ catch (NullListException)
+ {
+ _logger.LogError("NullListException");
+ return ClerkOperationResponse.NotFound("The list is not initialized");
+ }
+ catch (StorageException ex)
+ {
+ _logger.LogError(ex, "StorageException");
+ return ClerkOperationResponse.InternalServerError(
+ $"Error while working with data storage:{ex.InnerException!.Message}"
+ );
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Exception");
+ return ClerkOperationResponse.InternalServerError(ex.Message);
+ }
+ }
+
+ public ClerkOperationResponse GetElement(string data)
+ {
+ try
+ {
+ return ClerkOperationResponse.OK(
+ _mapper.Map(_clerkBusinessLogicContract.GetClerkByData(data))
+ );
+ }
+ catch (ArgumentNullException ex)
+ {
+ _logger.LogError(ex, "ArgumentNullException");
+ return ClerkOperationResponse.BadRequest("Data is empty");
+ }
+ catch (ElementNotFoundException ex)
+ {
+ _logger.LogError(ex, "ElementNotFoundException");
+ return ClerkOperationResponse.NotFound($"Not found element by data {data}");
+ }
+ catch (StorageException ex)
+ {
+ _logger.LogError(ex, "StorageException");
+ return ClerkOperationResponse.InternalServerError(
+ $"Error while working with data storage: {ex.InnerException!.Message}"
+ );
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Exception");
+ return ClerkOperationResponse.InternalServerError(ex.Message);
+ }
+ }
+
+ public ClerkOperationResponse RegisterClerk(ClerkBindingModel clerkDataModel)
+ {
+ try
+ {
+ _clerkBusinessLogicContract.InsertClerk(_mapper.Map(clerkDataModel));
+ return ClerkOperationResponse.NoContent();
+ }
+ catch (ArgumentNullException ex)
+ {
+ _logger.LogError(ex, "ArgumentNullException");
+ return ClerkOperationResponse.BadRequest("Data is empty");
+ }
+ catch (ValidationException ex)
+ {
+ _logger.LogError(ex, "ValidationException");
+ return ClerkOperationResponse.BadRequest($"Incorrect data transmitted: {ex.Message}");
+ }
+ catch (ElementExistsException ex)
+ {
+ _logger.LogError(ex, "ElementExistsException");
+ return ClerkOperationResponse.BadRequest(ex.Message);
+ }
+ catch (StorageException ex)
+ {
+ _logger.LogError(ex, "StorageException");
+ return ClerkOperationResponse.BadRequest(
+ $"Error while working with data storage: {ex.InnerException!.Message}"
+ );
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Exception");
+ return ClerkOperationResponse.InternalServerError(ex.Message);
+ }
+ }
+
+ public ClerkOperationResponse ChangeClerkInfo(ClerkBindingModel clerkDataModel)
+ {
+ try
+ {
+ _clerkBusinessLogicContract.UpdateClerk(_mapper.Map(clerkDataModel));
+ return ClerkOperationResponse.NoContent();
+ }
+ catch (ArgumentNullException ex)
+ {
+ _logger.LogError(ex, "ArgumentNullException");
+ return ClerkOperationResponse.BadRequest("Data is empty");
+ }
+ catch (ValidationException ex)
+ {
+ _logger.LogError(ex, "ValidationException");
+ return ClerkOperationResponse.BadRequest($"Incorrect data transmitted: {ex.Message}");
+ }
+ catch (ElementNotFoundException ex)
+ {
+ _logger.LogError(ex, "ElementNotFoundException");
+ return ClerkOperationResponse.BadRequest(
+ $"Not found element by Id {clerkDataModel.Id}"
+ );
+ }
+ catch (ElementExistsException ex)
+ {
+ _logger.LogError(ex, "ElementExistsException");
+ return ClerkOperationResponse.BadRequest(ex.Message);
+ }
+ catch (StorageException ex)
+ {
+ _logger.LogError(ex, "StorageException");
+ return ClerkOperationResponse.BadRequest(
+ $"Error while working with data storage: {ex.InnerException!.Message}"
+ );
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Exception");
+ return ClerkOperationResponse.InternalServerError(ex.Message);
+ }
+ }
+}
diff --git a/TheBank/BankWebApi/AuthOptions.cs b/TheBank/BankWebApi/AuthOptions.cs
new file mode 100644
index 0000000..f9e7702
--- /dev/null
+++ b/TheBank/BankWebApi/AuthOptions.cs
@@ -0,0 +1,16 @@
+using Microsoft.IdentityModel.Tokens;
+using System.Text;
+
+namespace BankWebApi;
+
+///
+/// настройки для авторизации
+/// переделаем потом если не будет впадлу
+///
+public class AuthOptions
+{
+ public const string ISSUER = "Bank_AuthServer"; // издатель токена
+ public const string AUDIENCE = "Bank_AuthClient"; // потребитель токена
+ const string KEY = "banksuperpupersecret_secretsecretsecretkey!"; // ключ для шифрации
+ public static SymmetricSecurityKey GetSymmetricSecurityKey() => new(Encoding.UTF8.GetBytes(KEY));
+}
diff --git a/TheBank/BankWebApi/BankWebApi.csproj b/TheBank/BankWebApi/BankWebApi.csproj
new file mode 100644
index 0000000..5abea56
--- /dev/null
+++ b/TheBank/BankWebApi/BankWebApi.csproj
@@ -0,0 +1,26 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TheBank/BankWebApi/BankWebApi.http b/TheBank/BankWebApi/BankWebApi.http
new file mode 100644
index 0000000..d07a81d
--- /dev/null
+++ b/TheBank/BankWebApi/BankWebApi.http
@@ -0,0 +1,6 @@
+@BankWebApi_HostAddress = http://localhost:5189
+
+GET {{BankWebApi_HostAddress}}/weatherforecast/
+Accept: application/json
+
+###
diff --git a/TheBank/BankWebApi/Controllers/ClerksController.cs b/TheBank/BankWebApi/Controllers/ClerksController.cs
new file mode 100644
index 0000000..45245ab
--- /dev/null
+++ b/TheBank/BankWebApi/Controllers/ClerksController.cs
@@ -0,0 +1,39 @@
+using BankContracts.AdapterContracts;
+using BankContracts.BindingModels;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace BankWebApi.Controllers;
+
+[Authorize]
+[Route("api/[controller]")]
+[ApiController]
+[Produces("application/json")]
+public class ClerksController(IClerkAdapter adapter) : ControllerBase
+{
+ private readonly IClerkAdapter _adapter = adapter;
+
+ [HttpGet]
+ public IActionResult GetAllRecords()
+ {
+ return _adapter.GetList().GetResponse(Request, Response);
+ }
+
+ [HttpGet("{data}")]
+ public IActionResult GetRecord(string data)
+ {
+ return _adapter.GetElement(data).GetResponse(Request, Response);
+ }
+
+ [HttpPost]
+ public IActionResult Register([FromBody] ClerkBindingModel model)
+ {
+ return _adapter.RegisterClerk(model).GetResponse(Request, Response);
+ }
+
+ [HttpPut]
+ public IActionResult ChangeInfo([FromBody] ClerkBindingModel model)
+ {
+ return _adapter.ChangeClerkInfo(model).GetResponse(Request, Response);
+ }
+}
diff --git a/TheBank/BankWebApi/Infrastructure/ConfigurationDatabase.cs b/TheBank/BankWebApi/Infrastructure/ConfigurationDatabase.cs
new file mode 100644
index 0000000..3c9e747
--- /dev/null
+++ b/TheBank/BankWebApi/Infrastructure/ConfigurationDatabase.cs
@@ -0,0 +1,14 @@
+using BankContracts.Infrastructure;
+
+namespace BankWebApi.Infrastructure;
+
+public class ConfigurationDatabase(IConfiguration configuration) : IConfigurationDatabase
+{
+ private readonly Lazy _dataBaseSettings = new(() =>
+ {
+ return configuration.GetSection("DataBaseSettings").Get()
+ ?? throw new InvalidDataException("DataBaseSettings section is missing or invalid.");
+ });
+
+ public string ConnectionString => _dataBaseSettings.Value.ConnectionString;
+}
diff --git a/TheBank/BankWebApi/Infrastructure/DataBaseSettings.cs b/TheBank/BankWebApi/Infrastructure/DataBaseSettings.cs
new file mode 100644
index 0000000..c38498e
--- /dev/null
+++ b/TheBank/BankWebApi/Infrastructure/DataBaseSettings.cs
@@ -0,0 +1,6 @@
+namespace BankWebApi.Infrastructure;
+
+public class DataBaseSettings
+{
+ public required string ConnectionString { get; set; }
+}
diff --git a/TheBank/BankWebApi/Program.cs b/TheBank/BankWebApi/Program.cs
new file mode 100644
index 0000000..751ffa7
--- /dev/null
+++ b/TheBank/BankWebApi/Program.cs
@@ -0,0 +1,93 @@
+using BankBusinessLogic.Implementations;
+using BankContracts.AdapterContracts;
+using BankContracts.BusinessLogicContracts;
+using BankContracts.Infrastructure;
+using BankContracts.StorageContracts;
+using BankDatabase;
+using BankDatabase.Implementations;
+using BankWebApi;
+using BankWebApi.Adapters;
+using BankWebApi.Infrastructure;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.IdentityModel.Tokens;
+using Serilog;
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Claims;
+
+var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+
+builder.Services.AddControllers();
+using var loggerFactory = new LoggerFactory();
+loggerFactory.AddSerilog(new LoggerConfiguration().ReadFrom.Configuration(builder.Configuration).CreateLogger());
+builder.Services.AddSingleton(loggerFactory.CreateLogger("Any"));
+
+builder.Services.AddAuthorization();
+builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+ .AddJwtBearer(options =>
+ {
+ options.TokenValidationParameters = new TokenValidationParameters
+ {
+
+ ValidateIssuer = true,
+
+ ValidIssuer = AuthOptions.ISSUER,
+
+ ValidateAudience = true,
+
+ ValidAudience = AuthOptions.AUDIENCE,
+
+ ValidateLifetime = true,
+
+ IssuerSigningKey = AuthOptions.GetSymmetricSecurityKey(),
+
+ ValidateIssuerSigningKey = true,
+ };
+ });
+
+// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
+builder.Services.AddOpenApi();
+builder.Services.AddSingleton();
+//
+builder.Services.AddTransient();
+//
+builder.Services.AddTransient();
+builder.Services.AddTransient();
+//
+builder.Services.AddTransient();
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (app.Environment.IsDevelopment())
+{
+ app.MapOpenApi();
+}
+if (app.Environment.IsProduction())
+{
+ var dbContext = app.Services.GetRequiredService();
+ if (dbContext.Database.CanConnect())
+ {
+ dbContext.Database.EnsureCreated();
+ dbContext.Database.Migrate();
+ }
+}
+
+app.UseHttpsRedirection();
+
+app.UseAuthorization();
+
+app.Map("/login/{username}", (string username) =>
+{
+ return new JwtSecurityTokenHandler().WriteToken(new JwtSecurityToken(
+ issuer: AuthOptions.ISSUER,
+ audience: AuthOptions.AUDIENCE,
+ claims: [new(ClaimTypes.Name, username)],
+ expires: DateTime.UtcNow.Add(TimeSpan.FromMinutes(2)),
+ signingCredentials: new SigningCredentials(AuthOptions.GetSymmetricSecurityKey(), SecurityAlgorithms.HmacSha256)));
+});
+
+app.MapControllers();
+
+app.Run();
diff --git a/TheBank/BankWebApi/Properties/launchSettings.json b/TheBank/BankWebApi/Properties/launchSettings.json
new file mode 100644
index 0000000..13b957b
--- /dev/null
+++ b/TheBank/BankWebApi/Properties/launchSettings.json
@@ -0,0 +1,23 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": false,
+ "applicationUrl": "http://localhost:5189",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": false,
+ "applicationUrl": "https://localhost:7204;http://localhost:5189",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/TheBank/BankWebApi/appsettings.Development.json b/TheBank/BankWebApi/appsettings.Development.json
new file mode 100644
index 0000000..0c208ae
--- /dev/null
+++ b/TheBank/BankWebApi/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/TheBank/BankWebApi/appsettings.json b/TheBank/BankWebApi/appsettings.json
new file mode 100644
index 0000000..758c5cb
--- /dev/null
+++ b/TheBank/BankWebApi/appsettings.json
@@ -0,0 +1,28 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "Serilog": {
+ "Using": [ "Serilog.Sinks.File" ],
+ "MinimumLevel": {
+ "Default": "Information"
+ },
+ "WriteTo": [
+ {
+ "Name": "File",
+ "Args": {
+ "path": "../logs/bank-.log",
+ "rollingInterval": "Day",
+ "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {CorrelationId} {Level:u3} {Username} {Message:lj} {Exception} {NewLine},"
+ }
+ }
+ ]
+ },
+ "DataBaseSettings": {
+ "ConnectionString": "Host=127.0.0.1;Port=5432;Database=BankTest;Username=postgres;Password=admin123;"
+ },
+ "AllowedHosts": "*"
+}
\ No newline at end of file
diff --git a/TheBank/TheBank.sln b/TheBank/TheBank.sln
index d28ceae..3b390b3 100644
--- a/TheBank/TheBank.sln
+++ b/TheBank/TheBank.sln
@@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BankDatabase", "BankDatabas
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BankTests", "BankTests\BankTests.csproj", "{7C898FC8-6BC2-41E8-9538-D42ACC263A97}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BankWebApi", "BankWebApi\BankWebApi.csproj", "{C8A3A3BB-A096-429F-A763-5465C5CB735F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -33,6 +35,10 @@ Global
{7C898FC8-6BC2-41E8-9538-D42ACC263A97}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C898FC8-6BC2-41E8-9538-D42ACC263A97}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C898FC8-6BC2-41E8-9538-D42ACC263A97}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C8A3A3BB-A096-429F-A763-5465C5CB735F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C8A3A3BB-A096-429F-A763-5465C5CB735F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C8A3A3BB-A096-429F-A763-5465C5CB735F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C8A3A3BB-A096-429F-A763-5465C5CB735F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE