diff --git a/WatchIt.Common/WatchIt.Common.Model/Persons/PersonRequest.cs b/WatchIt.Common/WatchIt.Common.Model/Persons/PersonRequest.cs index 7db15a2..5379e05 100644 --- a/WatchIt.Common/WatchIt.Common.Model/Persons/PersonRequest.cs +++ b/WatchIt.Common/WatchIt.Common.Model/Persons/PersonRequest.cs @@ -25,5 +25,15 @@ public class PersonRequest : Person GenderId = GenderId, }; + public void UpdatePerson(Database.Model.Person.Person person) + { + person.Name = Name; + person.FullName = FullName; + person.Description = Description; + person.BirthDate = BirthDate; + person.DeathDate = DeathDate; + person.GenderId = GenderId; + } + #endregion } \ No newline at end of file diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/PersonsController.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/PersonsController.cs index b527c75..aaf1d45 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/PersonsController.cs +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/PersonsController.cs @@ -1,4 +1,9 @@ +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using WatchIt.Common.Model.Persons; +using WatchIt.WebAPI.Services.Controllers.Persons; namespace WatchIt.WebAPI.Controllers; @@ -7,8 +12,73 @@ namespace WatchIt.WebAPI.Controllers; public class PersonsController : ControllerBase { #region SERVICES + + private readonly IPersonsControllerService _personsControllerService; + + #endregion + #region CONSTRUCTORS + + public PersonsController(IPersonsControllerService personsControllerService) + { + _personsControllerService = personsControllerService; + } + + #endregion + + + + #region METHODS + + #region Main + + [HttpGet] + [AllowAnonymous] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public async Task GetAllMovies(PersonQueryParameters query) => await _personsControllerService.GetAllPersons(query); + + [HttpGet("{id}")] + [AllowAnonymous] + [ProducesResponseType(typeof(PersonResponse), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GetMovie([FromRoute] long id) => await _personsControllerService.GetPerson(id); + + [HttpPost] + [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] + [ProducesResponseType(typeof(PersonResponse), StatusCodes.Status201Created)] + [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)] + public async Task PostMovie([FromBody] PersonRequest body) => await _personsControllerService.PostPerson(body); + + [HttpPut("{id}")] + [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] + [ProducesResponseType(typeof(void), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)] + public async Task PutMovie([FromRoute] long id, [FromBody]PersonRequest body) => await _personsControllerService.PutPerson(id, body); + + [HttpDelete("{id}")] + [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] + [ProducesResponseType(typeof(void), StatusCodes.Status204NoContent)] + [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)] + public async Task DeleteMovie([FromRoute] long id) => await _personsControllerService.DeletePerson(id); + + #endregion + + #region View count + + [HttpGet("view")] + [AllowAnonymous] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task GetMoviesViewRank([FromQuery] int first = 5, [FromQuery] int days = 7) => await _personsControllerService.GetPersonsViewRank(first, days); + + #endregion + #endregion } \ No newline at end of file diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/WatchIt.WebAPI.Controllers.csproj b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/WatchIt.WebAPI.Controllers.csproj index 809068e..b254b7e 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/WatchIt.WebAPI.Controllers.csproj +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/WatchIt.WebAPI.Controllers.csproj @@ -17,6 +17,7 @@ + diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/IPersonsControllerService.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/IPersonsControllerService.cs new file mode 100644 index 0000000..f9b5f6f --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/IPersonsControllerService.cs @@ -0,0 +1,14 @@ +using WatchIt.Common.Model.Persons; +using WatchIt.WebAPI.Services.Controllers.Common; + +namespace WatchIt.WebAPI.Services.Controllers.Persons; + +public interface IPersonsControllerService +{ + Task GetAllPersons(PersonQueryParameters query); + Task GetPerson(long id); + Task PostPerson(PersonRequest data); + Task PutPerson(long id, PersonRequest data); + Task DeletePerson(long id); + Task GetPersonsViewRank(int first, int days); +} \ No newline at end of file diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/PersonsControllerService.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/PersonsControllerService.cs index 9f8af1d..09137fe 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/PersonsControllerService.cs +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/PersonsControllerService.cs @@ -7,7 +7,7 @@ using Person = WatchIt.Database.Model.Person.Person; namespace WatchIt.WebAPI.Services.Controllers.Persons; -public class PersonsControllerService +public class PersonsControllerService : IPersonsControllerService { #region SERVICES @@ -42,7 +42,7 @@ public class PersonsControllerService return RequestResult.Ok(data); } - public async Task GetMovie(long id) + public async Task GetPerson(long id) { Person? item = await _database.Persons.FirstOrDefaultAsync(x => x.Id == id); if (item is null) @@ -69,6 +69,77 @@ public class PersonsControllerService return RequestResult.Created($"persons/{personItem.Id}", new PersonResponse(personItem)); } + public async Task PutPerson(long id, PersonRequest data) + { + UserValidator validator = _userService.GetValidator().MustBeAdmin(); + if (!validator.IsValid) + { + return RequestResult.Forbidden(); + } + + Person? item = await _database.Persons.FirstOrDefaultAsync(x => x.Id == id); + if (item is null) + { + return RequestResult.NotFound(); + } + + data.UpdatePerson(item); + + await _database.SaveChangesAsync(); + + return RequestResult.Ok(); + } + + public async Task DeletePerson(long id) + { + UserValidator validator = _userService.GetValidator().MustBeAdmin(); + if (!validator.IsValid) + { + return RequestResult.Forbidden(); + } + + Person? item = await _database.Persons.FirstOrDefaultAsync(x => x.Id == id); + if (item is null) + { + return RequestResult.NotFound(); + } + + _database.PersonCreatorRoles.AttachRange(item.PersonCreatorRoles); + _database.PersonCreatorRoles.RemoveRange(item.PersonCreatorRoles); + _database.PersonActorRoles.AttachRange(item.PersonActorRoles); + _database.PersonActorRoles.RemoveRange(item.PersonActorRoles); + _database.ViewCountsPerson.AttachRange(item.ViewCountsPerson); + _database.ViewCountsPerson.RemoveRange(item.ViewCountsPerson); + _database.Persons.Attach(item); + _database.Persons.Remove(item); + await _database.SaveChangesAsync(); + + return RequestResult.NoContent(); + } + + #endregion + + #region View count + + public async Task GetPersonsViewRank(int first, int days) + { + if (first < 1 || days < 1) + { + return RequestResult.BadRequest(); + } + + DateOnly startDate = DateOnly.FromDateTime(DateTime.Now).AddDays(-days); + IEnumerable rawData = await _database.Persons.OrderByDescending(x => x.ViewCountsPerson.Where(y => y.Date >= startDate) + .Sum(y => y.ViewCount)) + .ThenBy(x => x.Id) + .Take(first) + .ToListAsync(); + + IEnumerable data = rawData.Select(x => new PersonResponse(x)); + + return RequestResult.Ok(data); + } + #endregion #endregion diff --git a/WatchIt.WebAPI/WatchIt.WebAPI/Program.cs b/WatchIt.WebAPI/WatchIt.WebAPI/Program.cs index 7bd902b..4e2c243 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI/Program.cs +++ b/WatchIt.WebAPI/WatchIt.WebAPI/Program.cs @@ -13,6 +13,7 @@ using WatchIt.WebAPI.Services.Controllers.Accounts; using WatchIt.WebAPI.Services.Controllers.Genres; using WatchIt.WebAPI.Services.Controllers.Media; using WatchIt.WebAPI.Services.Controllers.Movies; +using WatchIt.WebAPI.Services.Controllers.Persons; using WatchIt.WebAPI.Services.Controllers.Photos; using WatchIt.WebAPI.Services.Controllers.Series; using WatchIt.WebAPI.Services.Utility.Configuration; @@ -158,6 +159,7 @@ public static class Program builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); + builder.Services.AddTransient(); return builder; } diff --git a/WatchIt.WebAPI/WatchIt.WebAPI/WatchIt.WebAPI.csproj b/WatchIt.WebAPI/WatchIt.WebAPI/WatchIt.WebAPI.csproj index 5c06b61..37917aa 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI/WatchIt.WebAPI.csproj +++ b/WatchIt.WebAPI/WatchIt.WebAPI/WatchIt.WebAPI.csproj @@ -27,6 +27,7 @@ + diff --git a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Endpoints.cs b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Endpoints.cs index 765dd46..ef20f7a 100644 --- a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Endpoints.cs +++ b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Endpoints.cs @@ -9,4 +9,5 @@ public class Endpoints public Movies Movies { get; set; } public Series Series { get; set; } public Photos Photos { get; set; } + public Persons Persons { get; set; } } \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Persons.cs b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Persons.cs new file mode 100644 index 0000000..1bf760a --- /dev/null +++ b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Persons.cs @@ -0,0 +1,12 @@ +namespace WatchIt.Website.Services.Utility.Configuration.Model; + +public class Persons +{ + public string Base { get; set; } + public string GetAllPersons { get; set; } + public string GetPerson { get; set; } + public string PostPerson { get; set; } + public string PutPerson { get; set; } + public string DeletePerson { get; set; } + public string GetPersonsViewRank { get; set; } +} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/IPersonsWebAPIService.cs b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/IPersonsWebAPIService.cs new file mode 100644 index 0000000..2f2181f --- /dev/null +++ b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/IPersonsWebAPIService.cs @@ -0,0 +1,13 @@ +using WatchIt.Common.Model.Persons; + +namespace WatchIt.Website.Services.WebAPI.Persons; + +public interface IPersonsWebAPIService +{ + Task GetAllPersons(PersonQueryParameters? query = null, Action>? successAction = null); + Task GetPerson(long id, Action? successAction = null, Action? notFoundAction = null); + Task PostPerson(PersonRequest data, Action? successAction = null, Action>? badRequestAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null); + Task PutPerson(long id, PersonRequest data, Action? successAction = null, Action>? badRequestAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null); + Task DeletePerson(long id, Action? successAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null); + Task GetPersonsViewRank(int? first = null, int? days = null, Action>? successAction = null, Action>? badRequestAction = null); +} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/PersonsWebAPIService.cs b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/PersonsWebAPIService.cs new file mode 100644 index 0000000..b19d450 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/PersonsWebAPIService.cs @@ -0,0 +1,152 @@ +using System.Text; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Primitives; +using WatchIt.Common.Model.Persons; +using WatchIt.Common.Services.HttpClient; +using WatchIt.Website.Services.Utility.Configuration; +using WatchIt.Website.Services.WebAPI.Common; + +namespace WatchIt.Website.Services.WebAPI.Persons; + +public class PersonsWebAPIService : BaseWebAPIService, IPersonsWebAPIService +{ + #region SERVICES + + private IHttpClientService _httpClientService; + private IConfigurationService _configurationService; + + #endregion + + + + #region CONSTRUCTORS + + public PersonsWebAPIService(IHttpClientService httpClientService, IConfigurationService configurationService) : base(configurationService) + { + _httpClientService = httpClientService; + _configurationService = configurationService; + } + + #endregion + + + + #region PUBLIC METHODS + + #region Main + + public async Task GetAllPersons(PersonQueryParameters? query = null, Action>? successAction = null) + { + string url = GetUrl(EndpointsConfiguration.Persons.GetAllPersons); + + HttpRequest request = new HttpRequest(HttpMethodType.Get, url); + request.Query = query; + + HttpResponse response = await _httpClientService.SendRequestAsync(request); + response.RegisterActionFor2XXSuccess(successAction) + .ExecuteAction(); + } + + public async Task GetPerson(long id, Action? successAction = null, Action? notFoundAction = null) + { + string url = GetUrl(EndpointsConfiguration.Persons.GetPerson, id); + + HttpRequest request = new HttpRequest(HttpMethodType.Get, url); + + HttpResponse response = await _httpClientService.SendRequestAsync(request); + response.RegisterActionFor2XXSuccess(successAction) + .RegisterActionFor404NotFound(notFoundAction) + .ExecuteAction(); + } + + public async Task PostPerson(PersonRequest data, Action? successAction = null, Action>? badRequestAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null) + { + string url = GetUrl(EndpointsConfiguration.Persons.PostPerson); + + HttpRequest request = new HttpRequest(HttpMethodType.Post, url); + request.Body = data; + + HttpResponse response = await _httpClientService.SendRequestAsync(request); + response.RegisterActionFor2XXSuccess(successAction) + .RegisterActionFor400BadRequest(badRequestAction) + .RegisterActionFor401Unauthorized(unauthorizedAction) + .RegisterActionFor403Forbidden(forbiddenAction) + .ExecuteAction(); + } + + public async Task PutPerson(long id, PersonRequest data, Action? successAction = null, Action>? badRequestAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null) + { + string url = GetUrl(EndpointsConfiguration.Persons.PutPerson, id); + + HttpRequest request = new HttpRequest(HttpMethodType.Put, url); + request.Body = data; + + HttpResponse response = await _httpClientService.SendRequestAsync(request); + response.RegisterActionFor2XXSuccess(successAction) + .RegisterActionFor400BadRequest(badRequestAction) + .RegisterActionFor401Unauthorized(unauthorizedAction) + .RegisterActionFor403Forbidden(forbiddenAction) + .ExecuteAction(); + } + + public async Task DeletePerson(long id, Action? successAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null) + { + string url = GetUrl(EndpointsConfiguration.Persons.DeletePerson, id); + + HttpRequest request = new HttpRequest(HttpMethodType.Delete, url); + + HttpResponse response = await _httpClientService.SendRequestAsync(request); + response.RegisterActionFor2XXSuccess(successAction) + .RegisterActionFor401Unauthorized(unauthorizedAction) + .RegisterActionFor403Forbidden(forbiddenAction) + .ExecuteAction(); + } + + #endregion + + #region View count + + public async Task GetPersonsViewRank(int? first = null, int? days = null, Action>? successAction = null, Action>? badRequestAction = null) + { + string url = GetUrl(EndpointsConfiguration.Persons.GetPersonsViewRank); + if (first.HasValue || days.HasValue) + { + StringBuilder urlBuilder = new StringBuilder(url); + urlBuilder.Append('?'); + bool firstParameter = true; + if (first.HasValue) + { + urlBuilder.Append($"first={first.Value}"); + firstParameter = false; + } + if (days.HasValue) + { + if (!firstParameter) + { + urlBuilder.Append('&'); + } + urlBuilder.Append($"days={days.Value}"); + } + url = urlBuilder.ToString(); + } + + HttpRequest request = new HttpRequest(HttpMethodType.Get, url); + + HttpResponse response = await _httpClientService.SendRequestAsync(request); + response.RegisterActionFor2XXSuccess(successAction) + .RegisterActionFor400BadRequest(badRequestAction) + .ExecuteAction(); + } + + #endregion + + #endregion + + + + #region PRIVATE METHODS + + protected override string GetServiceBase() => EndpointsConfiguration.Persons.Base; + + #endregion +} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/WatchIt.Website.Services.WebAPI.Persons.csproj b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/WatchIt.Website.Services.WebAPI.Persons.csproj new file mode 100644 index 0000000..abf3359 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/WatchIt.Website.Services.WebAPI.Persons.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + enable + enable + + + + + + + + diff --git a/WatchIt.Website/WatchIt.Website/appsettings.json b/WatchIt.Website/WatchIt.Website/appsettings.json index 02e7c38..ab714ae 100644 --- a/WatchIt.Website/WatchIt.Website/appsettings.json +++ b/WatchIt.Website/WatchIt.Website/appsettings.json @@ -70,6 +70,15 @@ "DeletePhoto": "/{0}", "PutPhotoBackgroundData": "/{0}/background_data", "DeletePhotoBackgroundData": "/{0}/background_data" + }, + "Persons": { + "Base": "/persons", + "GetAllPersons": "", + "GetPerson": "/{0}", + "PostPerson": "", + "PutPerson": "/{0}", + "DeletePerson": "/{0}", + "GetPersonsViewRank": "/view" } } } diff --git a/WatchIt.sln b/WatchIt.sln index 5346bd4..92de90e 100644 --- a/WatchIt.sln +++ b/WatchIt.sln @@ -90,6 +90,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.Website.Services.We EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.WebAPI.Services.Controllers.Persons", "WatchIt.WebAPI\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Controllers\WatchIt.WebAPI.Services.Controllers.Persons\WatchIt.WebAPI.Services.Controllers.Persons.csproj", "{335686F5-65B8-4D66-AAA8-C5032906451D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.Website.Services.WebAPI.Persons", "WatchIt.Website\WatchIt.Website.Services\WatchIt.Website.Services.WebAPI\WatchIt.Website.Services.WebAPI.Persons\WatchIt.Website.Services.WebAPI.Persons.csproj", "{83D42D72-FF67-4577-8280-2ABD5B20F985}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -137,6 +139,7 @@ Global {ABDF8471-2FAB-4930-B016-7DD3E48AE6B8} = {CEC468DB-CC49-47D3-9E3E-1CC9530C3CE7} {960A833F-C195-4D1D-AD4F-D00B57067181} = {46E3711F-18BD-4004-AF53-EA4D8643D92F} {335686F5-65B8-4D66-AAA8-C5032906451D} = {CEC468DB-CC49-47D3-9E3E-1CC9530C3CE7} + {83D42D72-FF67-4577-8280-2ABD5B20F985} = {46E3711F-18BD-4004-AF53-EA4D8643D92F} EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {23383776-1F27-4B5D-8C7C-57BFF75FA473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -271,5 +274,9 @@ Global {335686F5-65B8-4D66-AAA8-C5032906451D}.Debug|Any CPU.Build.0 = Debug|Any CPU {335686F5-65B8-4D66-AAA8-C5032906451D}.Release|Any CPU.ActiveCfg = Release|Any CPU {335686F5-65B8-4D66-AAA8-C5032906451D}.Release|Any CPU.Build.0 = Release|Any CPU + {83D42D72-FF67-4577-8280-2ABD5B20F985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {83D42D72-FF67-4577-8280-2ABD5B20F985}.Debug|Any CPU.Build.0 = Debug|Any CPU + {83D42D72-FF67-4577-8280-2ABD5B20F985}.Release|Any CPU.ActiveCfg = Release|Any CPU + {83D42D72-FF67-4577-8280-2ABD5B20F985}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal