diff --git a/GameData.UnitTests/GameData.UnitTests.csproj b/GameData.UnitTests/GameData.UnitTests.csproj
new file mode 100644
index 0000000..d82adde
--- /dev/null
+++ b/GameData.UnitTests/GameData.UnitTests.csproj
@@ -0,0 +1,24 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GameData.UnitTests/GlobalUsings.cs b/GameData.UnitTests/GlobalUsings.cs
new file mode 100644
index 0000000..cefced4
--- /dev/null
+++ b/GameData.UnitTests/GlobalUsings.cs
@@ -0,0 +1 @@
+global using NUnit.Framework;
\ No newline at end of file
diff --git a/GameData.UnitTests/UnitTest1.cs b/GameData.UnitTests/UnitTest1.cs
new file mode 100644
index 0000000..19e71d1
--- /dev/null
+++ b/GameData.UnitTests/UnitTest1.cs
@@ -0,0 +1,21 @@
+using GameData.Repository;
+using GameModel;
+using System.Data.Common;
+
+namespace GameData.UnitTests
+{
+ public class Tests
+ {
+ [SetUp]
+ public void Setup()
+ {
+ }
+
+ [Test]
+ public void Test1()
+ {
+ var client = new ExpenseRepository();
+ var test = client.GetAll();
+ }
+ }
+}
\ No newline at end of file
diff --git a/GameData/ApiClient.cs b/GameData/ApiClient.cs
new file mode 100644
index 0000000..9629a36
--- /dev/null
+++ b/GameData/ApiClient.cs
@@ -0,0 +1,260 @@
+using GameData.Repository;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http.Headers;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web;
+
+namespace GameData
+{
+ public sealed class ApiClient : IDisposable
+ {
+ private class Wrapper
+ {
+ public T[] Data { get; set; }
+ }
+
+ private readonly HttpClient client;
+ private readonly string _apiKey = "9wIqngBjwR_l2f89D0EEAN1ldrcXUl6c";
+ private readonly string Api = "https://directus.straso.com/";
+ public ApiClient()
+ {
+ client = new HttpClient
+ {
+ Timeout = TimeSpan.FromMinutes(1)
+ };
+
+ client.DefaultRequestHeaders
+ .Accept
+ .Add(new MediaTypeWithQualityHeaderValue("application/json"));
+
+ client.DefaultRequestHeaders
+ .Authorization = new AuthenticationHeaderValue("Bearer", _apiKey);
+
+ //client.DefaultRequestHeaders.Add("Api-AppInfo", "KrahApp;" + Assembly.GetExecutingAssembly().GetName().Version.ToString());
+
+ if (!Api.EndsWith("/"))
+ {
+ Api += "/";
+ }
+ }
+
+ public void Dispose()
+ {
+ client.Dispose();
+ }
+
+ public string UrlEncode(string s)
+ {
+ return HttpUtility.UrlEncode(s);
+ }
+
+ private string GetFullUrl(string url)
+ {
+ if (url[0].Equals('/'))
+ {
+ url = url.Remove(0, 1);
+ }
+
+ url = Api + url;
+ return url;
+ }
+
+ private HttpRequestMessage GetHttpRequestMessage(HttpMethod method, string serviceUrl, object payload = null)
+ {
+ StringContent content = null;
+ if (payload != null)
+ {
+ var payloadString = JsonConvert.SerializeObject(payload);
+ content = new StringContent(payloadString, Encoding.UTF8, "application/json");
+ }
+
+ var url = serviceUrl;
+ if (!serviceUrl.StartsWith("http", StringComparison.InvariantCultureIgnoreCase))
+ {
+ url = GetFullUrl(serviceUrl);
+ }
+
+ var res = new HttpRequestMessage
+ {
+ Content = content,
+ Method = method,
+ RequestUri = new Uri(url),
+ };
+ //res.Headers.Add("Authorization: Bearer", _apiKey);
+ return res;
+ }
+
+ public async Task DownloadFile(string serviceUrl, string targetFile)
+ {
+ var res = false;
+ try
+ {
+ var request = GetHttpRequestMessage(HttpMethod.Get, serviceUrl);
+ request.Headers.Add("Accept", "application/json");
+ request.Headers.Add("Accept", "application/octet-stream");
+ request.Headers.Add("Accept", "file/download");
+
+ var response = await client.SendAsync(request);
+
+ if (response.IsSuccessStatusCode)
+ {
+ using (var responseStream = await response.Content.ReadAsStreamAsync())
+ {
+ using (var fileStream = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true))
+ {
+ await responseStream.CopyToAsync(fileStream);
+ res = true;
+ }
+ }
+ }
+ else
+ {
+ var errorResult = await response.Content.ReadAsStringAsync();
+ //_logger.LogError("error downloading from service '{service}' with code '{statuscode}' - Result: '{result}', TargetFile: '{payload}'", serviceUrl, response.StatusCode, errorResult, targetFile);
+ }
+ }
+ catch (Exception ex)
+ {
+ //_logger.LogError(ex, "error at DownloadFile");
+ }
+
+ return res;
+ }
+
+ public async Task Post(object payload, string serviceUrl, bool suppressExceptions = true)
+ {
+ T res = default;
+
+ try
+ {
+ var response = await client.SendAsync(GetHttpRequestMessage(HttpMethod.Post, serviceUrl, payload));
+
+ if (response.IsSuccessStatusCode)
+ {
+ using (var responseStream = await response.Content.ReadAsStreamAsync())
+ {
+ using (var streamReader = new StreamReader(responseStream))
+ {
+ using (var jsonTextReader = new JsonTextReader(streamReader))
+ {
+ var serializer = new JsonSerializer();
+ res = serializer.Deserialize(jsonTextReader);
+ }
+ }
+ }
+ }
+ else
+ {
+ var errorResult = await response.Content.ReadAsStringAsync();
+ //_logger.LogError("error posting to service '{service}' with code '{statuscode}' - Result: '{result}', Payload: '{payload}'", serviceUrl, response.StatusCode, errorResult, JsonConvert.SerializeObject(payload));
+ }
+ }
+ catch (Exception ex)
+ {
+ //_logger.LogError(ex, "error at post");
+ if (!suppressExceptions)
+ {
+ throw ex;
+ }
+ }
+
+ return res;
+ }
+
+ public async Task Delete(object payload, string serviceUrl, bool suppressExceptions = true)
+ {
+ T res = default;
+
+ try
+ {
+ var response = await client.SendAsync(GetHttpRequestMessage(HttpMethod.Delete, serviceUrl, payload));
+
+ if (response.IsSuccessStatusCode)
+ {
+ using (var responseStream = await response.Content.ReadAsStreamAsync())
+ {
+ using (var streamReader = new StreamReader(responseStream))
+ {
+ using (var jsonTextReader = new JsonTextReader(streamReader))
+ {
+ var serializer = new JsonSerializer();
+ res = serializer.Deserialize(jsonTextReader);
+ }
+ }
+ }
+ }
+ else
+ {
+ var errorResult = await response.Content.ReadAsStringAsync();
+ //_logger.LogError("error deleting to service '{service}' with code '{statuscode}' - Result: '{result}', Payload: '{payload}'", serviceUrl, response.StatusCode, errorResult, JsonConvert.SerializeObject(payload));
+ }
+ }
+ catch (Exception ex)
+ {
+ //_logger.LogError(ex, "error at Delete");
+ if (!suppressExceptions)
+ {
+ throw ex;
+ }
+ }
+
+ return res;
+ }
+
+ public T[] Get(string serviceUrl, bool suppressExceptions = true)
+ {
+ Wrapper res = default;
+
+ try
+ {
+ //_logger.LogDebug($"calling service url {serviceUrl}");
+ var response = client.Send(GetHttpRequestMessage(HttpMethod.Get, serviceUrl));
+
+ if (response.IsSuccessStatusCode)
+ {
+ using (var responseStream = response.Content.ReadAsStream())
+ {
+ using (var streamReader = new StreamReader(responseStream))
+ {
+ string content;
+ if (typeof(T).Equals(typeof(string)))
+ {
+ content = streamReader.ReadToEnd();
+ res = (Wrapper)Convert.ChangeType(content, typeof(T));
+ }
+ else
+ {
+ using (var jsonTextReader = new JsonTextReader(streamReader))
+ {
+ var serializer = new JsonSerializer();
+ //serializer.
+ res = serializer.Deserialize>(jsonTextReader);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ var errorResult = response.Content.ReadAsStringAsync();
+ //_logger.LogError("error getting from service '{service}' with code '{statuscode}' - Result: '{result}'", serviceUrl, response.StatusCode, errorResult);
+ }
+ }
+ catch (Exception ex)
+ {
+ //_logger.LogError(ex, "error at Get");
+ if (!suppressExceptions)
+ {
+ throw ex;
+ }
+ }
+
+ return res.Data;
+ }
+ }
+}
diff --git a/GameData/ApiSettings.cs b/GameData/ApiSettings.cs
new file mode 100644
index 0000000..cc59cab
--- /dev/null
+++ b/GameData/ApiSettings.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GameData
+{
+ public class ApiSettings
+ {
+ public string BaseUrl => "https://directus.straso.com/";
+ public string ApiToken => "9wIqngBjwR_l2f89D0EEAN1ldrcXUl6c";
+
+
+ }
+}
diff --git a/GameData/ContainerSetup.cs b/GameData/ContainerSetup.cs
new file mode 100644
index 0000000..b608e6f
--- /dev/null
+++ b/GameData/ContainerSetup.cs
@@ -0,0 +1,25 @@
+using Autofac;
+using GameData.Dummy;
+using GameData.Repository;
+using GameModel.Contract;
+using GameModel.Settings;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GameData
+{
+ //public static class ContainerSetup
+ //{
+ // public static Autofac.IContainer GetContainer()
+ // {
+ // var builder = new ContainerBuilder();
+
+ // builder.RegisterType().As();
+ // return builder.Build();
+ // }
+ //}
+}
diff --git a/GameData/DummyExpenseRepository.cs b/GameData/Dummy/DummyExpenseRepository.cs
similarity index 90%
rename from GameData/DummyExpenseRepository.cs
rename to GameData/Dummy/DummyExpenseRepository.cs
index 61e8329..2954827 100644
--- a/GameData/DummyExpenseRepository.cs
+++ b/GameData/Dummy/DummyExpenseRepository.cs
@@ -1,7 +1,7 @@
using GameModel;
using GameModel.Contract;
-namespace GameData
+namespace GameData.Dummy
{
public class DummyExpenseRepository : IExpenseRepository
{
diff --git a/GameData/GameData.csproj b/GameData/GameData.csproj
index 044def4..8d810f8 100644
--- a/GameData/GameData.csproj
+++ b/GameData/GameData.csproj
@@ -6,6 +6,11 @@
enable
+
+
+
+
+
diff --git a/GameData/Repository/ExpenseRepository.cs b/GameData/Repository/ExpenseRepository.cs
new file mode 100644
index 0000000..4049940
--- /dev/null
+++ b/GameData/Repository/ExpenseRepository.cs
@@ -0,0 +1,27 @@
+using GameModel;
+using GameModel.Contract;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GameData.Repository
+{
+ public class ExpenseRepository : IExpenseRepository
+ {
+ private ApiClient _client;
+
+ string Url => "items/expense";
+
+ public ExpenseRepository()
+ {
+ _client = new ApiClient();
+ }
+
+ public IEnumerable GetAll()
+ {
+ return _client.Get(Url);
+ }
+ }
+}
diff --git a/GameHandler.UnitTests/Extensions/PinThrowExtensionTests.cs b/GameHandler.UnitTests/Extensions/PinThrowExtensionTests.cs
index d9b3300..dab2ca5 100644
--- a/GameHandler.UnitTests/Extensions/PinThrowExtensionTests.cs
+++ b/GameHandler.UnitTests/Extensions/PinThrowExtensionTests.cs
@@ -65,7 +65,7 @@ namespace GameHandler.UnitTests.Extensions
var bs = BoardState.Create(ThrowMode.Decrease);
var pt = PinThrow.Create(1, PinPicture.CreateAllPins(), false, true);
var tirgger = pt.GetExpenseTriggers(bs);
- CollectionAssert.AreEqual(tirgger, new[] { ExpenseTrigger.FullSink });
+ CollectionAssert.AreEqual(tirgger, new[] { ExpenseTrigger.SinkAtAll });
}
}
}
diff --git a/GameHandler.UnitTests/GameHandler/FreeGameHandlerTests.cs b/GameHandler.UnitTests/GameHandler/FreeGameHandlerTests.cs
index 0a9e49d..fedd3f6 100644
--- a/GameHandler.UnitTests/GameHandler/FreeGameHandlerTests.cs
+++ b/GameHandler.UnitTests/GameHandler/FreeGameHandlerTests.cs
@@ -29,11 +29,16 @@ namespace GameHandler.UnitTests.GameHandler
Assert.That(model.Throws.Count(), Is.EqualTo(4));
}
+ [Test]
+ public void Update_ThrowsExceptionWhenModelIsNull()
+ {
+ Assert.That(() => _gh.Update(PinThrow.Create(2, false, true), null, BoardState.Create()), Throws.TypeOf());
+ }
+
[Test]
public void Update_ThrowsExceptionWhenModelIsNotInitialized()
{
- Assert.That(() => _gh.Update(PinThrow.Create(2, false, true), BoardState.Create()), Throws.TypeOf());
-
+ Assert.That(() => _gh.Update(PinThrow.Create(2, false, true), new FreeGameModel(null,0,Array.Empty()), BoardState.Create()), Throws.TypeOf());
}
}
}
diff --git a/GameHandler/Extensions/PinThrowExtension.cs b/GameHandler/Extensions/PinThrowExtension.cs
index 21e624e..d8a7561 100644
--- a/GameHandler/Extensions/PinThrowExtension.cs
+++ b/GameHandler/Extensions/PinThrowExtension.cs
@@ -18,7 +18,7 @@ namespace GameHandler.Extensions
{
if (boardState.PinPicture.AllUp && boardState.ThrowMode == ThrowMode.Decrease)
{
- res.Add(ExpenseTrigger.FullSink);
+ res.Add(ExpenseTrigger.SinkAtAll);
}
else
{
diff --git a/GameHandler/GameHandler/FreeGameHandler.cs b/GameHandler/GameHandler/FreeGameHandler.cs
index 4c8ed8b..f8bfadb 100644
--- a/GameHandler/GameHandler/FreeGameHandler.cs
+++ b/GameHandler/GameHandler/FreeGameHandler.cs
@@ -32,6 +32,11 @@ namespace GameHandler.GameHandler
public IGameModel Update(PinThrow pinThrow, IGameModel gameModel, BoardState boardStateBeforeUpdate)
{
+ if (gameModel == null)
+ {
+ throw new ArgumentNullException("gameModel cannto be null");
+ }
+
var gm = gameModel as FreeGameModel;
var throws = gm.Throws.ToList();
diff --git a/GameModel/Contracts/IExpenseRepository.cs b/GameModel/Contracts/IExpenseRepository.cs
index 89831a9..aaacb4d 100644
--- a/GameModel/Contracts/IExpenseRepository.cs
+++ b/GameModel/Contracts/IExpenseRepository.cs
@@ -7,7 +7,7 @@ namespace GameModel.Contract
static Expense[] TestData = new[] {
Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.Sink }, "Gosse", 0.5m, false),
Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.Sink }, "Gosse2", 1.5m, false),
- Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.FullSink }, "Gosse bei Anwurf", 1m, false),
+ Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.SinkAtAll }, "Gosse bei Anwurf", 1m, false),
Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.Circle }, "Kranz", 1m, true),
Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.NinePins }, "alle Neune", 1m, true),
Expense.Create(ExpenseType.Monetary,new[] { ExpenseTrigger.Eliminated }, "Ausgeschieden", 0.5m, false),
diff --git a/GameModel/Expense.cs b/GameModel/Expense.cs
index 4691fef..82d9250 100644
--- a/GameModel/Expense.cs
+++ b/GameModel/Expense.cs
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace GameModel
{
- public record Expense(Guid Guid, ExpenseType ExpenseType, ExpenseTrigger[] ExpenseTriggers, string Name, decimal Price, bool IsInverse)
+ public record Expense(Guid Id, ExpenseType ExpenseType, ExpenseTrigger[] ExpenseTriggers, string Name, decimal Price, bool IsInverse)
{
public static Expense Create(ExpenseType ExpenseType, ExpenseTrigger[] ExpenseTriggers, string Name, decimal Price, bool IsInverse)
{
diff --git a/GameModel/ExpenseTrigger.cs b/GameModel/ExpenseTrigger.cs
index e75ae70..8e21dd2 100644
--- a/GameModel/ExpenseTrigger.cs
+++ b/GameModel/ExpenseTrigger.cs
@@ -17,7 +17,7 @@ namespace GameModel
///
/// Sink at first throw in round
///
- FullSink, // Gosse beim Anwurf
+ SinkAtAll, // Gosse beim Anwurf
Eliminated, // Ausgeschieden
Absent, // Am Spieltag nicht teilgenommen
ExpensePoint // Strafpunkt, z.B. im "Scheißspiel"
diff --git a/GameModel/MemberExpense.cs b/GameModel/MemberExpense.cs
index fc7604e..0ef6735 100644
--- a/GameModel/MemberExpense.cs
+++ b/GameModel/MemberExpense.cs
@@ -6,11 +6,11 @@ using System.Threading.Tasks;
namespace GameModel
{
- public record MemberExpense(Guid ExpenseGuid, int MemberId, ExpenseType ExpenseType, DateTime Created, decimal Price, string Name)
+ public record MemberExpense(Guid Id, int MemberId, Guid ExpenseId, ExpenseType ExpenseType, DateTime Created, decimal Price, string Name)
{
public static MemberExpense Create(int MemberId, Expense Expense)
{
- return new MemberExpense(Guid.NewGuid(), MemberId, Expense.ExpenseType, DateTime.Now, Expense.Price, Expense.Name);
+ return new MemberExpense(Guid.NewGuid(), MemberId, Expense.Id, Expense.ExpenseType, DateTime.Now, Expense.Price, Expense.Name);
}
}
}
diff --git a/GameModel/Settings/AppSettings.cs b/GameModel/Settings/AppSettings.cs
new file mode 100644
index 0000000..e033ce6
--- /dev/null
+++ b/GameModel/Settings/AppSettings.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GameModel.Settings
+{
+ public class AppSettings
+ {
+ public string Test { get; set; }
+ }
+}
diff --git a/KoogleCli/KoogleCli.csproj b/KoogleCli/KoogleCli.csproj
index caaf8eb..8255d0c 100644
--- a/KoogleCli/KoogleCli.csproj
+++ b/KoogleCli/KoogleCli.csproj
@@ -1,4 +1,4 @@
-
+
Exe
@@ -7,8 +7,22 @@
enable
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+
diff --git a/KoogleCli/Program.cs b/KoogleCli/Program.cs
index d1043d0..1a2d38c 100644
--- a/KoogleCli/Program.cs
+++ b/KoogleCli/Program.cs
@@ -2,18 +2,75 @@
using Autofac;
using CommandLine;
using GameData;
+using GameData.Repository;
using GameHandler;
using GameHandler.DeathGame;
using GameHandler.Extensions;
using GameModel;
using GameModel.Contract;
using GameModel.DeathGame;
+using GameModel.Settings;
using KoogleCli.Model;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
using Spectre.Console;
using Spectre.Console.Json;
using static System.Runtime.InteropServices.JavaScript.JSType;
+
+const string RootLifetimeTag = "MyIsolatedRoot";
+
+
+
AnsiConsole.MarkupLine("Welcome to [green]koogle[/]");
+
+
+var container = Register();
+
+var serviceCollection = new ServiceCollection();
+//serviceCollection.AddLogging();
+
+
+var scope = container.BeginLifetimeScope(RootLifetimeTag, b =>
+{
+ //b.Populate(serviceCollection, RootLifetimeTag);
+});
+
+
+Autofac.IContainer Register()
+{
+
+ var configurationBuilder = new ConfigurationBuilder()
+ .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
+ .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
+ //.AddXmlFile("appsettings.xml", optional: true, reloadOnChange: true)
+ //.AddEnvironmentVariables()
+ //.AddCommandLine(args);
+ ;
+
+ // Add your custom configuration provider here if needed
+ // .Add(new CustomConfigurationSource());
+
+ IConfiguration configuration = configurationBuilder.Build();
+
+
+
+ var someSettings = configuration.GetSection(typeof(AppSettings).Name).Get();
+
+
+ var builder = new ContainerBuilder();
+ builder.RegisterInstance(someSettings);
+ builder.RegisterType().As();
+ return builder.Build();
+}
+
+
+
+var test = container.Resolve();
+Console.WriteLine( test.Test);
+Console.ReadLine();
+
ShowMainMenu();
void ShowMainMenu()
{
@@ -78,7 +135,7 @@ void NewGameAction()
void StartGameAction(string gameName)
{
- _gs = new GameService(GetContainer());
+ _gs = new GameService();
var bs = _gs.Start(new[] { 1,2,3,4}, GetGameSettings(gameName), gameName );
@@ -120,13 +177,6 @@ void StartGameAction(string gameName)
ShowMainMenu();
}
-IContainer GetContainer()
-{
- var builder = new ContainerBuilder();
- builder.RegisterType().As();
- return builder.Build();
-}
-
IGameSettings GetGameSettings(string gameName)
{
if (gameName == DeathGameHandler.GAMENAME_DEATHBOX)
diff --git a/KoogleCli/appsettings.json b/KoogleCli/appsettings.json
new file mode 100644
index 0000000..7700910
--- /dev/null
+++ b/KoogleCli/appsettings.json
@@ -0,0 +1,5 @@
+{
+ "AppSettings": {
+ "Test": "value"
+ }
+}
diff --git a/KoogleV4.sln b/KoogleV4.sln
index 970ed25..13421f8 100644
--- a/KoogleV4.sln
+++ b/KoogleV4.sln
@@ -13,10 +13,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameModel.UnitTests", "Game
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KoogleCli", "KoogleCli\KoogleCli.csproj", "{3FF45A02-42F9-4E75-993B-6582DD2A22BF}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameData", "GameData\GameData.csproj", "{D026F84B-06F5-4BA4-8AB7-D1D385F0611C}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameData", "GameData\GameData.csproj", "{D026F84B-06F5-4BA4-8AB7-D1D385F0611C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{5DC1FCEB-EF9B-4BFD-9AEA-56B6B81E204B}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameData.UnitTests", "GameData.UnitTests\GameData.UnitTests.csproj", "{910C00EB-06CE-4EBC-9B76-DD290DC03AE8}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -47,6 +49,10 @@ Global
{D026F84B-06F5-4BA4-8AB7-D1D385F0611C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D026F84B-06F5-4BA4-8AB7-D1D385F0611C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D026F84B-06F5-4BA4-8AB7-D1D385F0611C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {910C00EB-06CE-4EBC-9B76-DD290DC03AE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {910C00EB-06CE-4EBC-9B76-DD290DC03AE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {910C00EB-06CE-4EBC-9B76-DD290DC03AE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {910C00EB-06CE-4EBC-9B76-DD290DC03AE8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -54,6 +60,7 @@ Global
GlobalSection(NestedProjects) = preSolution
{E2F3CE36-0051-4C9A-B3FF-0BB44292B756} = {5DC1FCEB-EF9B-4BFD-9AEA-56B6B81E204B}
{C752388E-815A-4911-AC75-B6C27337D81A} = {5DC1FCEB-EF9B-4BFD-9AEA-56B6B81E204B}
+ {910C00EB-06CE-4EBC-9B76-DD290DC03AE8} = {5DC1FCEB-EF9B-4BFD-9AEA-56B6B81E204B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {00DAFA57-4F14-4807-886E-392D4E67BA46}