Ping! Pong!
This commit is contained in:
commit
6de712910f
23
.gitignore
vendored
Normal file
23
.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Build results
|
||||||
|
[Bb]in/
|
||||||
|
.bin/
|
||||||
|
[Dd]ebug/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
[Oo]bj/
|
||||||
|
[Oo]ut/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
[Pp]ublish/
|
||||||
|
|
||||||
|
# IDE files
|
||||||
|
.vs/
|
||||||
|
.vscode/
|
||||||
|
.vshistory/
|
||||||
|
.idea/
|
||||||
|
с/
|
||||||
|
.editorconfig
|
||||||
|
*.user
|
||||||
|
|
||||||
|
#backups
|
||||||
|
.old*/
|
||||||
12
Directory.Build.props
Normal file
12
Directory.Build.props
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<EnablePreviewFeatures>True</EnablePreviewFeatures>
|
||||||
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<InvariantGlobalization>true</InvariantGlobalization>
|
||||||
|
<!-- System.Net.Quic not officially supported on some platforms -->
|
||||||
|
<NoWarn>CA1416</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
14
Meum.Client.CLI/Meum.Client.CLI.csproj
Normal file
14
Meum.Client.CLI/Meum.Client.CLI.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<Version>1.0.0</Version>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Meum.Client\Meum.Client.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="DTLib" Version="1.6.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
83
Meum.Client.CLI/Program.cs
Normal file
83
Meum.Client.CLI/Program.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
global using System;
|
||||||
|
global using System.Collections.Generic;
|
||||||
|
global using System.Threading;
|
||||||
|
global using System.Threading.Tasks;
|
||||||
|
global using Meum.Core;
|
||||||
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
|
using DTLib.Console;
|
||||||
|
using DTLib.Demystifier;
|
||||||
|
using DTLib.Extensions;
|
||||||
|
|
||||||
|
namespace Meum.Client.CLI;
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
private const string greeting_art =
|
||||||
|
"""
|
||||||
|
^,,^ ╱|
|
||||||
|
( •·•) Meum! (o.o`7
|
||||||
|
/ ` | Meum... |`˜ \
|
||||||
|
\(_,J J L l`,)/
|
||||||
|
""";
|
||||||
|
|
||||||
|
private const string farewell_art =
|
||||||
|
"""
|
||||||
|
^,,^ ╱|
|
||||||
|
( -.-) (>,<`7
|
||||||
|
/ ` | Goodbye! |`˜ \
|
||||||
|
\(_,J J L l`,)/
|
||||||
|
""";
|
||||||
|
|
||||||
|
static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
Console.OutputEncoding = StringConverter.UTF8;
|
||||||
|
Console.InputEncoding = StringConverter.UTF8;
|
||||||
|
ColoredConsole.ResetColor();
|
||||||
|
var v = Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
|
string title = $"Meum CLI v{v?.ToString(3) ?? "Null"}";
|
||||||
|
Console.Title = title;
|
||||||
|
ColoredConsole.WriteTitle(title, '=', fg: ConsoleColor.Cyan);
|
||||||
|
ColoredConsole.WriteLine(greeting_art, fg: ConsoleColor.Magenta);
|
||||||
|
ColoredConsole.WriteHLine('=', fg: ConsoleColor.Cyan);
|
||||||
|
|
||||||
|
UserAddress? userAddress = null;
|
||||||
|
DnsEndPoint? serverEndPoint = null;
|
||||||
|
string? serverAddress = null;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(userAddress == null)
|
||||||
|
{
|
||||||
|
var addrstr = ColoredConsole.ReadLine("enter user address (name@server.xyz)", ConsoleColor.Blue);
|
||||||
|
if (string.IsNullOrEmpty(addrstr))
|
||||||
|
continue;
|
||||||
|
userAddress = new(addrstr);
|
||||||
|
}
|
||||||
|
Client client = new(userAddress);
|
||||||
|
if(serverEndPoint == null)
|
||||||
|
{
|
||||||
|
serverAddress = ColoredConsole.ReadLine("enter server address (server.xyz)", ConsoleColor.Blue);
|
||||||
|
if (string.IsNullOrEmpty(serverAddress))
|
||||||
|
{
|
||||||
|
ColoredConsole.WriteLine("null address", ConsoleColor.Red);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
serverEndPoint = Network.ParseDnsEndPoint(serverAddress);
|
||||||
|
ColoredConsole.WriteTitle(serverAddress, fg: ConsoleColor.Cyan);
|
||||||
|
}
|
||||||
|
|
||||||
|
ColoredConsole.WriteLine("connecting to the server...", ConsoleColor.Blue);
|
||||||
|
var conn = await client.ConnectToServerAsync(serverEndPoint);
|
||||||
|
await conn.PingAsync();
|
||||||
|
await Task.Delay(-1);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ColoredConsole.WriteLine(ex.ToStringDemystified(), ConsoleColor.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ColoredConsole.ResetColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
29
Meum.Client/Client.cs
Normal file
29
Meum.Client/Client.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
global using System;
|
||||||
|
global using System.Collections.Generic;
|
||||||
|
global using System.Threading;
|
||||||
|
global using System.Threading.Tasks;
|
||||||
|
global using Meum.Core;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace Meum.Client;
|
||||||
|
|
||||||
|
public class Client
|
||||||
|
{
|
||||||
|
private readonly HashSet<ServerConnection> _connectedServers = new();
|
||||||
|
public IReadOnlySet<ServerConnection> ConnectedServers => _connectedServers;
|
||||||
|
|
||||||
|
public UserAddress Address { get; }
|
||||||
|
|
||||||
|
public Client(UserAddress address)
|
||||||
|
{
|
||||||
|
Address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServerConnection> ConnectToServerAsync(DnsEndPoint serverEndPoint)
|
||||||
|
{
|
||||||
|
var serv = new ServerConnection(serverEndPoint);
|
||||||
|
await serv.ConnectAsync();
|
||||||
|
_connectedServers.Add(serv);
|
||||||
|
return serv;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
Meum.Client/Meum.Client.csproj
Normal file
17
Meum.Client/Meum.Client.csproj
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Meum.Core\Meum.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="DTLib" Version="1.6.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
47
Meum.Client/ServerConnection.cs
Normal file
47
Meum.Client/ServerConnection.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Net.Quic;
|
||||||
|
using System.Net.Security;
|
||||||
|
using DTLib.Extensions;
|
||||||
|
|
||||||
|
namespace Meum.Client;
|
||||||
|
|
||||||
|
public class ServerConnection : IDisposable
|
||||||
|
{
|
||||||
|
public DnsEndPoint ServerEndPoint { get; }
|
||||||
|
|
||||||
|
private QuicConnection? _quicConnection;
|
||||||
|
|
||||||
|
public ServerConnection(DnsEndPoint serverEndPoint)
|
||||||
|
{
|
||||||
|
ServerEndPoint = serverEndPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ConnectAsync()
|
||||||
|
{
|
||||||
|
_quicConnection = await QuicConnection.ConnectAsync(new QuicClientConnectionOptions
|
||||||
|
{
|
||||||
|
RemoteEndPoint = new IPEndPoint(IPAddress.Loopback, Network.ServerPortDefault),
|
||||||
|
DefaultStreamErrorCode = Network.DefaultStreamErrorCode,
|
||||||
|
DefaultCloseErrorCode = Network.DefaultCloseErrorCode,
|
||||||
|
ClientAuthenticationOptions = new SslClientAuthenticationOptions
|
||||||
|
{
|
||||||
|
ApplicationProtocols = Network.ApplicationProtocols.ToList(),
|
||||||
|
TargetHost = ServerEndPoint.Host
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PingAsync()
|
||||||
|
{
|
||||||
|
var stream = await _quicConnection!.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);
|
||||||
|
await stream.WriteAsync("Ping\n".ToBytes());
|
||||||
|
StreamReader reader = new StreamReader(stream);
|
||||||
|
string line = await reader.ReadLineAsync() ?? String.Empty;
|
||||||
|
Console.WriteLine(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_quicConnection?.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
5
Meum.Core/Meum.Core.csproj
Normal file
5
Meum.Core/Meum.Core.csproj
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Unofficial.MsQuic" Version="2.4.6" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
47
Meum.Core/Network.cs
Normal file
47
Meum.Core/Network.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
global using System;
|
||||||
|
global using System.Collections.Generic;
|
||||||
|
global using System.Threading;
|
||||||
|
global using System.Threading.Tasks;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Security;
|
||||||
|
|
||||||
|
namespace Meum.Core;
|
||||||
|
|
||||||
|
public static class Network
|
||||||
|
{
|
||||||
|
public static readonly SslApplicationProtocol[] ApplicationProtocols =
|
||||||
|
[
|
||||||
|
new("Meum-1")
|
||||||
|
];
|
||||||
|
|
||||||
|
public const int ServerPortDefault = 9320;
|
||||||
|
public const long DefaultStreamErrorCode = 0xA;
|
||||||
|
public const long DefaultCloseErrorCode = 0xB;
|
||||||
|
|
||||||
|
|
||||||
|
public static bool IsValidDomainName(string name)
|
||||||
|
{
|
||||||
|
return Uri.CheckHostName(name) != UriHostNameType.Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DnsEndPoint ParseDnsEndPoint(string address_str)
|
||||||
|
{
|
||||||
|
string host;
|
||||||
|
int port;
|
||||||
|
int colon_index = address_str.IndexOf(':');
|
||||||
|
if (colon_index == -1)
|
||||||
|
{
|
||||||
|
host = address_str;
|
||||||
|
port = ServerPortDefault;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
host = address_str.Substring(0, colon_index);
|
||||||
|
port = Convert.ToInt32(address_str.Substring(colon_index + 1));
|
||||||
|
}
|
||||||
|
if(!IsValidDomainName(host))
|
||||||
|
throw new ArgumentException($"Invalid domain name '{host}'");
|
||||||
|
|
||||||
|
return new DnsEndPoint(host, port);
|
||||||
|
}
|
||||||
|
}
|
||||||
48
Meum.Core/UserAddress.cs
Normal file
48
Meum.Core/UserAddress.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace Meum.Core;
|
||||||
|
|
||||||
|
public class UserAddress
|
||||||
|
{
|
||||||
|
public readonly string Name;
|
||||||
|
public readonly DnsEndPoint RegistrationServer;
|
||||||
|
public readonly string Full;
|
||||||
|
|
||||||
|
public UserAddress(string name, DnsEndPoint registrationServer)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
RegistrationServer = registrationServer;
|
||||||
|
Full = $"{name}@{registrationServer}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserAddress(string addrstr)
|
||||||
|
{
|
||||||
|
int at_index = addrstr.IndexOf('@');
|
||||||
|
if(at_index == -1)
|
||||||
|
throw new FormatException($"Invalid user address format '{addrstr}'");
|
||||||
|
Full = addrstr;
|
||||||
|
Name = addrstr.Substring(0, at_index);
|
||||||
|
if(!ValidateName(Name))
|
||||||
|
throw new FormatException($"Invalid user name '{Name}' in address '{addrstr}'");
|
||||||
|
string serverstr = addrstr.Substring(at_index + 1);
|
||||||
|
|
||||||
|
RegistrationServer = Network.ParseDnsEndPoint(serverstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => Full;
|
||||||
|
|
||||||
|
public override int GetHashCode() => ToString().GetHashCode();
|
||||||
|
|
||||||
|
private static bool ValidateName(string? name)
|
||||||
|
{
|
||||||
|
if(string.IsNullOrEmpty(name))
|
||||||
|
return false;
|
||||||
|
foreach (char c in name)
|
||||||
|
{
|
||||||
|
if(!char.IsAsciiLetterOrDigit(c) && c != '.' && c != '-' && c != '_')
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Meum.Server/Config.cs
Normal file
11
Meum.Server/Config.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using Meum.Core;
|
||||||
|
|
||||||
|
namespace Meum.Server;
|
||||||
|
|
||||||
|
public class Config
|
||||||
|
{
|
||||||
|
public string listener_ip { get; set; } = "127.0.0.1";
|
||||||
|
public int listener_port { get; set; } = Network.ServerPortDefault;
|
||||||
|
public string certificate_path { get; set; } = "self-signed.pem";
|
||||||
|
public string? key_path { get; set; } = "self-signed.key";
|
||||||
|
}
|
||||||
13
Meum.Server/Meum.Server.csproj
Normal file
13
Meum.Server/Meum.Server.csproj
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Meum.Core\Meum.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="DTLib" Version="1.6.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
70
Meum.Server/Program.cs
Normal file
70
Meum.Server/Program.cs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
global using System;
|
||||||
|
global using System.Collections.Generic;
|
||||||
|
global using System.Threading;
|
||||||
|
global using System.Threading.Tasks;
|
||||||
|
global using Meum.Core;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Quic;
|
||||||
|
using System.Net.Security;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using DTLib.Console;
|
||||||
|
using DTLib.Demystifier;
|
||||||
|
using DTLib.Extensions;
|
||||||
|
|
||||||
|
namespace Meum.Server;
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var config = new Config();
|
||||||
|
var certificate = X509Certificate2.CreateFromPemFile(config.certificate_path, config.key_path);
|
||||||
|
if(!certificate.Verify())
|
||||||
|
throw new Exception("Certificate is not valid");
|
||||||
|
var serverConnectionOptions = new QuicServerConnectionOptions
|
||||||
|
{
|
||||||
|
DefaultStreamErrorCode = Network.DefaultStreamErrorCode,
|
||||||
|
DefaultCloseErrorCode = Network.DefaultCloseErrorCode,
|
||||||
|
ServerAuthenticationOptions = new SslServerAuthenticationOptions
|
||||||
|
{
|
||||||
|
ApplicationProtocols = Network.ApplicationProtocols.ToList(),
|
||||||
|
ServerCertificate = certificate,
|
||||||
|
ClientCertificateRequired = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var listenerOptions = new QuicListenerOptions
|
||||||
|
{
|
||||||
|
ListenEndPoint = new IPEndPoint(IPAddress.Parse(config.listener_ip), config.listener_port),
|
||||||
|
ApplicationProtocols = Network.ApplicationProtocols.ToList(),
|
||||||
|
ConnectionOptionsCallback = (_, _, _) => ValueTask.FromResult(serverConnectionOptions)
|
||||||
|
};
|
||||||
|
var listener = await QuicListener.ListenAsync(listenerOptions);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var conn = await listener.AcceptConnectionAsync();
|
||||||
|
var stream = await conn.AcceptInboundStreamAsync();
|
||||||
|
StreamReader reader = new(stream);
|
||||||
|
string line = await reader.ReadLineAsync() ?? "";
|
||||||
|
Console.WriteLine(line);
|
||||||
|
await stream.WriteAsync("Pong\n".ToBytes());
|
||||||
|
await conn.CloseAsync(Network.DefaultCloseErrorCode);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ColoredConsole.WriteLine(ex.ToStringDemystified(), ConsoleColor.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ColoredConsole.WriteLine(ex.ToStringDemystified(), ConsoleColor.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
Meum.Server/README.md
Normal file
4
Meum.Server/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
## Create self-signed certificate
|
||||||
|
```sh
|
||||||
|
dotnet dev-certs https -ep bin/Debug/net8.0/self-signed.pfx --trust --format PEM --no-password
|
||||||
|
```
|
||||||
39
Meum.sln
Normal file
39
Meum.sln
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meum.Server", "Meum.Server\Meum.Server.csproj", "{769D657F-488E-4794-AC12-F7894037CB84}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meum.Client.CLI", "Meum.Client.CLI\Meum.Client.CLI.csproj", "{1DA062F3-F4F6-4A67-AC66-281EEA7427C6}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meum.Core", "Meum.Core\Meum.Core.csproj", "{2A31C5C6-A8A8-4C7F-B913-1F6BBD906743}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution_items", "solution_items", "{9375C0E5-DB78-4E77-869B-F9F7DC2651D1}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
Directory.Build.props = Directory.Build.props
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meum.Client", "Meum.Client\Meum.Client.csproj", "{6DADE8A1-B363-4888-BB9B-72282B9AC769}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{769D657F-488E-4794-AC12-F7894037CB84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{769D657F-488E-4794-AC12-F7894037CB84}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{769D657F-488E-4794-AC12-F7894037CB84}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{769D657F-488E-4794-AC12-F7894037CB84}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1DA062F3-F4F6-4A67-AC66-281EEA7427C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1DA062F3-F4F6-4A67-AC66-281EEA7427C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1DA062F3-F4F6-4A67-AC66-281EEA7427C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1DA062F3-F4F6-4A67-AC66-281EEA7427C6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2A31C5C6-A8A8-4C7F-B913-1F6BBD906743}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2A31C5C6-A8A8-4C7F-B913-1F6BBD906743}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2A31C5C6-A8A8-4C7F-B913-1F6BBD906743}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2A31C5C6-A8A8-4C7F-B913-1F6BBD906743}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6DADE8A1-B363-4888-BB9B-72282B9AC769}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6DADE8A1-B363-4888-BB9B-72282B9AC769}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6DADE8A1-B363-4888-BB9B-72282B9AC769}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6DADE8A1-B363-4888-BB9B-72282B9AC769}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
Loading…
Reference in New Issue
Block a user