* AppRouterController.cs: chore: 提取公共模块,和 Play 共享。包括
AppRouter,Json,日志等 * csharp-sdk.sln: * RTM.csproj: * Common.csproj: * HttpUtils.cs: * Tests.cs: * JsonExtensions.cs: * Storage.csproj: * JustTest.cs: * AppRouterTest.cs: * AppRouterState.cs: * ObjectTest.cs: * Common.Test.csproj: * Common.Test.csproj: * AppRouterTest.cs: * Storage.Test.csproj: * AVObjectController.cs:
parent
68a047ba1e
commit
f171cee759
|
@ -1,64 +0,0 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
public class AppRouterController {
|
||||
private AppRouterState currentState;
|
||||
|
||||
private readonly SemaphoreSlim locker = new SemaphoreSlim(1);
|
||||
|
||||
public async Task<AppRouterState> Get(string appId) {
|
||||
if (string.IsNullOrEmpty(appId)) {
|
||||
throw new ArgumentNullException(nameof(appId));
|
||||
}
|
||||
|
||||
if (currentState != null && !currentState.IsExpired) {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
await locker.WaitAsync();
|
||||
try {
|
||||
if (currentState == null) {
|
||||
try {
|
||||
currentState = await QueryAsync(appId);
|
||||
} catch (Exception) {
|
||||
currentState = AppRouterState.GetFallbackServers(appId);
|
||||
}
|
||||
}
|
||||
return currentState;
|
||||
} finally {
|
||||
locker.Release();
|
||||
}
|
||||
}
|
||||
|
||||
async Task<AppRouterState> QueryAsync(string appId) {
|
||||
Console.WriteLine("QueryAsync");
|
||||
|
||||
string url = string.Format("https://app-router.com/2/route?appId={0}", appId);
|
||||
|
||||
HttpClient client = new HttpClient();
|
||||
HttpRequestMessage request = new HttpRequestMessage {
|
||||
RequestUri = new Uri(url),
|
||||
Method = HttpMethod.Get
|
||||
};
|
||||
|
||||
HttpResponseMessage response = await client.SendAsync(request);
|
||||
client.Dispose();
|
||||
request.Dispose();
|
||||
|
||||
string content = await response.Content.ReadAsStringAsync();
|
||||
response.Dispose();
|
||||
|
||||
AppRouterState state = JsonConvert.DeserializeObject<AppRouterState>(content);
|
||||
state.Source = "router";
|
||||
return state;
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
currentState = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LeanCloud.Common {
|
||||
public class AppRouterController {
|
||||
private AppRouterState currentState;
|
||||
|
||||
private readonly SemaphoreSlim locker = new SemaphoreSlim(1);
|
||||
|
||||
public async Task<AppRouterState> Get(string appId) {
|
||||
if (string.IsNullOrEmpty(appId)) {
|
||||
throw new ArgumentNullException(nameof(appId));
|
||||
}
|
||||
|
||||
if (currentState != null && !currentState.IsExpired) {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
await locker.WaitAsync();
|
||||
try {
|
||||
if (currentState == null) {
|
||||
try {
|
||||
currentState = await QueryAsync(appId);
|
||||
} catch (Exception) {
|
||||
currentState = AppRouterState.GetFallbackServers(appId);
|
||||
}
|
||||
}
|
||||
return currentState;
|
||||
} finally {
|
||||
locker.Release();
|
||||
}
|
||||
}
|
||||
|
||||
async Task<AppRouterState> QueryAsync(string appId) {
|
||||
HttpClient client = null;
|
||||
HttpRequestMessage request = null;
|
||||
HttpResponseMessage response = null;
|
||||
|
||||
try {
|
||||
string url = string.Format("https://app-router.com/2/route?appId={0}", appId);
|
||||
|
||||
client = new HttpClient();
|
||||
request = new HttpRequestMessage {
|
||||
RequestUri = new Uri(url),
|
||||
Method = HttpMethod.Get
|
||||
};
|
||||
HttpUtils.PrintRequest(client, request);
|
||||
|
||||
response = await client.SendAsync(request);
|
||||
string content = await response.Content.ReadAsStringAsync();
|
||||
HttpUtils.PrintResponse(response);
|
||||
|
||||
AppRouterState state = JsonConvert.DeserializeObject<AppRouterState>(content);
|
||||
state.Source = "router";
|
||||
|
||||
return state;
|
||||
} finally {
|
||||
if (client != null) {
|
||||
client.Dispose();
|
||||
}
|
||||
if (request != null) {
|
||||
request.Dispose();
|
||||
}
|
||||
if (response != null) {
|
||||
response.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
currentState = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
namespace LeanCloud.Common {
|
||||
public class AppRouterState {
|
||||
const string EAST_CHINA_SUFFIX = "-9Nh9j0Va";
|
||||
const string US_SUFFIX = "-MdYXbMMI";
|
||||
|
@ -93,6 +93,5 @@ namespace LeanCloud.Storage.Internal {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Log\" />
|
||||
<Folder Include="Http\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,49 @@
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace LeanCloud.Common {
|
||||
public class HttpUtils {
|
||||
public static void PrintRequest(HttpClient client, HttpRequestMessage request, string content = null) {
|
||||
if (client == null) {
|
||||
return;
|
||||
}
|
||||
if (request == null) {
|
||||
return;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("=== HTTP Request Start ===");
|
||||
sb.AppendLine($"URL: {request.RequestUri}");
|
||||
sb.AppendLine($"Method: {request.Method}");
|
||||
sb.AppendLine($"Headers: ");
|
||||
foreach (var header in client.DefaultRequestHeaders) {
|
||||
sb.AppendLine($"\t{header.Key}: {string.Join(",", header.Value.ToArray())}");
|
||||
}
|
||||
foreach (var header in request.Headers) {
|
||||
sb.AppendLine($"\t{header.Key}: {string.Join(",", header.Value.ToArray())}");
|
||||
}
|
||||
if (request.Content != null) {
|
||||
foreach (var header in request.Content.Headers) {
|
||||
sb.AppendLine($"\t{header.Key}: {string.Join(",", header.Value.ToArray())}");
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(content)) {
|
||||
sb.AppendLine($"Content: {content}");
|
||||
}
|
||||
sb.AppendLine("=== HTTP Request End ===");
|
||||
Logger.Debug(sb.ToString());
|
||||
}
|
||||
|
||||
public static void PrintResponse(HttpResponseMessage response, string content = null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("=== HTTP Response Start ===");
|
||||
sb.AppendLine($"URL: {response.RequestMessage.RequestUri}");
|
||||
sb.AppendLine($"Status Code: {response.StatusCode}");
|
||||
if (!string.IsNullOrEmpty(content)) {
|
||||
sb.AppendLine($"Content: {content}");
|
||||
}
|
||||
sb.AppendLine("=== HTTP Response End ===");
|
||||
Logger.Debug(sb.ToString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
namespace LeanCloud.Common {
|
||||
/// <summary>
|
||||
/// 为 Json 解析提供异步接口
|
||||
/// </summary>
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<ReleaseVersion>0.1.0</ReleaseVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -9,7 +10,6 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Storage\Storage\Storage.csproj" />
|
||||
<ProjectReference Include="..\..\AppRouter\AppRouter\AppRouter.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Internal\WebSocket\Unity\websocket-sharp.dll" />
|
||||
|
|
|
@ -6,11 +6,7 @@ namespace LeanCloud.Test {
|
|||
public class AppRouterTest {
|
||||
[Test]
|
||||
public async Task GetServers() {
|
||||
var appRouter = new AppRouterController();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
var state = await appRouter.Get("BMYV4RKSTwo8WSqt8q9ezcWF-gzGzoHsz");
|
||||
TestContext.Out.WriteLine(state.ApiServer);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,16 @@ namespace LeanCloud.Test {
|
|||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Zip() {
|
||||
List<int> l1 = new List<int> { 1, 2, 3, 4 };
|
||||
List<int> l2 = new List<int> { 1, 1, 2 };
|
||||
var l3 = l1.Zip(l2, (e1, e2) => $"{e1}-{e2}");
|
||||
foreach (var e in l3) {
|
||||
TestContext.Out.WriteLine($"{e}");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GenericType() {
|
||||
List<int> list = new List<int> { 1, 1, 2, 3, 5, 8 };
|
||||
|
|
|
@ -167,11 +167,21 @@ namespace LeanCloud.Test {
|
|||
List<AVObject> objList = new List<AVObject>();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
AVObject obj = AVObject.Create("Foo");
|
||||
obj.ACL = new AVACL {
|
||||
PublicReadAccess = true,
|
||||
PublicWriteAccess = i % 2 == 0
|
||||
};
|
||||
obj["content"] = "batch object";
|
||||
objList.Add(obj);
|
||||
}
|
||||
await objList.SaveAllAsync();
|
||||
await AVObject.DeleteAllAsync(objList);
|
||||
try {
|
||||
await AVObject.DeleteAllAsync(objList);
|
||||
} catch (AggregateException e) {
|
||||
foreach (AVException ie in e.InnerExceptions) {
|
||||
TestContext.Out.WriteLine($"{ie.Code} : {ie.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
@ -16,6 +16,5 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Storage\Storage.csproj" />
|
||||
<ProjectReference Include="..\..\AppRouter\AppRouter\AppRouter.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -122,7 +122,7 @@ namespace LeanCloud.Storage.Internal {
|
|||
return tasks;
|
||||
}
|
||||
|
||||
private IList<Task<IDictionary<string, object>>> ExecuteBatchRequest(IList<AVCommand> requests,
|
||||
private async Task<IList<Task<IDictionary<string, object>>>> ExecuteBatchRequest(IList<AVCommand> requests,
|
||||
CancellationToken cancellationToken) {
|
||||
var tasks = new List<Task<IDictionary<string, object>>>();
|
||||
int batchSize = requests.Count;
|
||||
|
@ -151,26 +151,16 @@ namespace LeanCloud.Storage.Internal {
|
|||
{ "requests", encodedRequests }
|
||||
}
|
||||
};
|
||||
AVPlugins.Instance.CommandRunner.RunCommandAsync<IList<object>>(command, cancellationToken).ContinueWith(t => {
|
||||
if (t.IsFaulted || t.IsCanceled) {
|
||||
foreach (var tcs in tcss) {
|
||||
if (t.IsFaulted) {
|
||||
tcs.TrySetException(t.Exception);
|
||||
} else if (t.IsCanceled) {
|
||||
tcs.TrySetCanceled();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var resultsArray = t.Result.Item2;
|
||||
try {
|
||||
var response = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IList<object>>(command, cancellationToken);
|
||||
var resultsArray = response.Item2;
|
||||
int resultLength = resultsArray.Count;
|
||||
if (resultLength != batchSize) {
|
||||
foreach (var tcs in tcss) {
|
||||
tcs.TrySetException(new InvalidOperationException(
|
||||
"Batch command result count expected: " + batchSize + " but was: " + resultLength + "."));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < batchSize; ++i) {
|
||||
|
@ -188,9 +178,11 @@ namespace LeanCloud.Storage.Internal {
|
|||
"Invalid batch command response."));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return tasks;
|
||||
} catch (Exception e) {
|
||||
foreach (var tcs in tcss) {
|
||||
tcs.TrySetException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\AppRouter\AppRouter\AppRouter.csproj" />
|
||||
<ProjectReference Include="..\..\Common\Common.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using LeanCloud.Common;
|
||||
|
||||
namespace Common.Test {
|
||||
public class Tests {
|
||||
static void Print(LogLevel level, string info) {
|
||||
switch (level) {
|
||||
case LogLevel.Debug:
|
||||
TestContext.Out.WriteLine($"[DEBUG] {info}");
|
||||
break;
|
||||
case LogLevel.Warn:
|
||||
TestContext.Out.WriteLine($"[WARNING] {info}");
|
||||
break;
|
||||
case LogLevel.Error:
|
||||
TestContext.Out.WriteLine($"[ERROR] {info}");
|
||||
break;
|
||||
default:
|
||||
TestContext.Out.WriteLine(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() {
|
||||
TestContext.Out.WriteLine("Set up");
|
||||
Logger.LogDelegate += Print;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown() {
|
||||
TestContext.Out.WriteLine("Tear down");
|
||||
Logger.LogDelegate -= Print;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task AppRouter() {
|
||||
var appRouter = new AppRouterController();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
var state = await appRouter.Get("BMYV4RKSTwo8WSqt8q9ezcWF-gzGzoHsz");
|
||||
TestContext.Out.WriteLine(state.ApiServer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="nunit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Common\Common.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -27,14 +27,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiveQuery.Test", "LiveQuery
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Storage.Test", "Storage\Storage.Test\Storage.Test.csproj", "{BE05B492-78CD-47CA-9F48-C3E9B4813AFF}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AppRouter", "AppRouter", "{1F05195D-2CAA-4214-8DAE-FE14A6B905DD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppRouter", "AppRouter\AppRouter\AppRouter.csproj", "{D34FC092-042A-44CE-A9E2-56B996BDCF42}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Storage", "Storage\Storage\Storage.csproj", "{59DA32A0-4CD3-424A-8584-D08B8D1E2B98}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RTM", "RTM\RTM\RTM.csproj", "{D4A30F70-AAED-415D-B940-023B3D7241EE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "Common\Common.csproj", "{14EC150A-EF90-4E0B-B6D7-C2CF1945F6E5}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{C827DA2F-6AB4-48D8-AB5B-6DAB925F8933}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.Test", "Test\Common.Test\Common.Test.csproj", "{4DF4E0F4-1013-477F-ADA6-BFAFD9312335}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -77,10 +79,6 @@ Global
|
|||
{BE05B492-78CD-47CA-9F48-C3E9B4813AFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BE05B492-78CD-47CA-9F48-C3E9B4813AFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BE05B492-78CD-47CA-9F48-C3E9B4813AFF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D34FC092-042A-44CE-A9E2-56B996BDCF42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D34FC092-042A-44CE-A9E2-56B996BDCF42}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D34FC092-042A-44CE-A9E2-56B996BDCF42}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D34FC092-042A-44CE-A9E2-56B996BDCF42}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{59DA32A0-4CD3-424A-8584-D08B8D1E2B98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{59DA32A0-4CD3-424A-8584-D08B8D1E2B98}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{59DA32A0-4CD3-424A-8584-D08B8D1E2B98}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
@ -89,6 +87,14 @@ Global
|
|||
{D4A30F70-AAED-415D-B940-023B3D7241EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D4A30F70-AAED-415D-B940-023B3D7241EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D4A30F70-AAED-415D-B940-023B3D7241EE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{14EC150A-EF90-4E0B-B6D7-C2CF1945F6E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{14EC150A-EF90-4E0B-B6D7-C2CF1945F6E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{14EC150A-EF90-4E0B-B6D7-C2CF1945F6E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{14EC150A-EF90-4E0B-B6D7-C2CF1945F6E5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4DF4E0F4-1013-477F-ADA6-BFAFD9312335}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4DF4E0F4-1013-477F-ADA6-BFAFD9312335}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4DF4E0F4-1013-477F-ADA6-BFAFD9312335}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4DF4E0F4-1013-477F-ADA6-BFAFD9312335}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{659D19F0-9A40-42C0-886C-555E64F16848} = {CD6B6669-1A56-437A-932E-BCE7F5D4CD18}
|
||||
|
@ -100,9 +106,9 @@ Global
|
|||
{3251B4D8-D11A-4D90-8626-27FEE266B066} = {5B895B7A-1F6E-40A5-8081-43B334D2C076}
|
||||
{F907012C-74DF-4575-AFE6-E8DAACC26D24} = {5B895B7A-1F6E-40A5-8081-43B334D2C076}
|
||||
{BE05B492-78CD-47CA-9F48-C3E9B4813AFF} = {CD6B6669-1A56-437A-932E-BCE7F5D4CD18}
|
||||
{D34FC092-042A-44CE-A9E2-56B996BDCF42} = {1F05195D-2CAA-4214-8DAE-FE14A6B905DD}
|
||||
{59DA32A0-4CD3-424A-8584-D08B8D1E2B98} = {CD6B6669-1A56-437A-932E-BCE7F5D4CD18}
|
||||
{D4A30F70-AAED-415D-B940-023B3D7241EE} = {64D8F9A1-BA44-459C-817C-788B4EBC0B9F}
|
||||
{4DF4E0F4-1013-477F-ADA6-BFAFD9312335} = {C827DA2F-6AB4-48D8-AB5B-6DAB925F8933}
|
||||
EndGlobalSection
|
||||
GlobalSection(MonoDevelopProperties) = preSolution
|
||||
version = 0.1.0
|
||||
|
|
Loading…
Reference in New Issue