A Core/NosSmooth.Cryptography/ClientLoginCryptography.cs => Core/NosSmooth.Cryptography/ClientLoginCryptography.cs +41 -0
@@ 0,0 1,41 @@
+//
+// ClientLoginCryptography.cs
+//
+// Copyright (c) František Boháček. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Text;
+
+namespace NosSmooth.Cryptography;
+
+/// <summary>
+/// A cryptography used for logging to NosTale server from the client.
+/// </summary>
+public class ClientLoginCryptography : ICryptography
+{
+ private static readonly Random Random = new Random(DateTime.Now.Millisecond);
+
+ /// <inheritdoc />
+ public string Decrypt(in ReadOnlySpan<byte> bytes, Encoding encoding)
+ {
+ var output = new StringBuilder();
+ foreach (var c in bytes)
+ {
+ output.Append(Convert.ToChar(c - 0xF));
+ }
+
+ return output.ToString();
+ }
+
+ /// <inheritdoc />
+ public byte[] Encrypt(string value, Encoding encoding)
+ {
+ var output = new byte[value.Length + 1];
+ for (int i = 0; i < value.Length; i++)
+ {
+ output[i] = (byte)((value[i] ^ 0xC3) + 0xF);
+ }
+ output[output.Length - 1] = 0xD8;
+ return output;
+ }
+}<
\ No newline at end of file
A Core/NosSmooth.Cryptography/ClientWorldCryptography.cs => Core/NosSmooth.Cryptography/ClientWorldCryptography.cs +311 -0
@@ 0,0 1,311 @@
+//
+// ClientWorldCryptography.cs
+//
+// Copyright (c) František Boháček. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Text;
+
+namespace NosSmooth.Cryptography;
+
+/// <summary>
+/// A cryptography used on world server, has to have a session id (encryption key) set from the client.
+/// </summary>
+public class ClientWorldCryptography : ICryptography
+{
+ private static readonly char[] Keys = { ' ', '-', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'n' };
+
+ /// <summary>
+ /// Gets or sets the encryption key.
+ /// </summary>
+ public int EncryptionKey { get; set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ClientWorldCryptography"/> class.
+ /// </summary>
+ /// <param name="encryptionKey">Encryption key received by LoginServer.</param>
+ public ClientWorldCryptography(int encryptionKey = 0)
+ {
+ EncryptionKey = encryptionKey;
+ }
+
+ /// <inheritdoc />
+ public string Decrypt(in ReadOnlySpan<byte> bytes, Encoding encoding)
+ {
+ int index = 0;
+ var currentPacket = new StringBuilder();
+
+ while (index < bytes.Length)
+ {
+ byte currentByte = bytes[index++];
+
+ if (currentByte == 0xFF)
+ {
+ currentPacket.Append('\n');
+ continue;
+ }
+
+ int length = currentByte & 0x7F;
+
+ if ((currentByte & 0x80) != 0)
+ {
+ while (length != 0)
+ {
+ if (index < bytes.Length)
+ {
+ currentByte = bytes[index++];
+ int firstIndex = (currentByte & 0xF0) >> 4;
+ char first = '?';
+ if (firstIndex != 0)
+ {
+ firstIndex--;
+ first = firstIndex != 14 ? Keys[firstIndex] : '\u0000';
+ }
+
+ if (first != 0x6E)
+ {
+ currentPacket.Append(first);
+ }
+
+ if (length <= 1)
+ {
+ break;
+ }
+
+ int secondIndex = currentByte & 0xF;
+ char second = '?';
+ if (secondIndex != 0)
+ {
+ secondIndex--;
+ second = secondIndex != 14 ? Keys[secondIndex] : '\u0000';
+ }
+
+ if (second != 0x6E)
+ {
+ currentPacket.Append(second);
+ }
+
+ length -= 2;
+ }
+ else
+ {
+ length--;
+ }
+ }
+ }
+ else
+ {
+ while (length != 0)
+ {
+ if (index < bytes.Length)
+ {
+ currentPacket.Append((char)(bytes[index] ^ 0xFF));
+ index++;
+ }
+ else if (index == bytes.Length)
+ {
+ currentPacket.Append((char)0xFF);
+ index++;
+ }
+
+ length--;
+ }
+ }
+ }
+
+ return currentPacket.ToString();
+ }
+
+ /// <inheritdoc />
+ public byte[] Encrypt(string value, Encoding encoding)
+ {
+ var output = new List<byte>();
+
+ string mask = new string
+ (
+ value.Select
+ (
+ c =>
+ {
+ sbyte b = (sbyte)c;
+ if (c == '#' || c == '/' || c == '%')
+ {
+ return '0';
+ }
+
+ if ((b -= 0x20) == 0 || (b += unchecked((sbyte)0xF1)) < 0 || (b -= 0xB) < 0 ||
+ b - unchecked((sbyte)0xC5) == 0)
+ {
+ return '1';
+ }
+
+ return '0';
+ }
+ ).ToArray()
+ );
+
+ int packetLength = value.Length;
+
+ int sequenceCounter = 0;
+ int currentPosition = 0;
+
+ while (currentPosition <= packetLength)
+ {
+ int lastPosition = currentPosition;
+ while (currentPosition < packetLength && mask[currentPosition] == '0')
+ {
+ currentPosition++;
+ }
+
+ int sequences;
+ int length;
+
+ if (currentPosition != 0)
+ {
+ length = currentPosition - lastPosition;
+ sequences = length / 0x7E;
+ for (int i = 0; i < length; i++, lastPosition++)
+ {
+ if (i == sequenceCounter * 0x7E)
+ {
+ if (sequences == 0)
+ {
+ output.Add((byte)(length - i));
+ }
+ else
+ {
+ output.Add(0x7E);
+ sequences--;
+ sequenceCounter++;
+ }
+ }
+
+ output.Add((byte)((byte)value[lastPosition] ^ 0xFF));
+ }
+ }
+
+ if (currentPosition >= packetLength)
+ {
+ break;
+ }
+
+ lastPosition = currentPosition;
+ while (currentPosition < packetLength && mask[currentPosition] == '1')
+ {
+ currentPosition++;
+ }
+
+ if (currentPosition == 0)
+ {
+ continue;
+ }
+
+ length = currentPosition - lastPosition;
+ sequences = length / 0x7E;
+ for (int i = 0; i < length; i++, lastPosition++)
+ {
+ if (i == sequenceCounter * 0x7E)
+ {
+ if (sequences == 0)
+ {
+ output.Add((byte)((length - i) | 0x80));
+ }
+ else
+ {
+ output.Add(0x7E | 0x80);
+ sequences--;
+ sequenceCounter++;
+ }
+ }
+
+ byte currentByte = (byte)value[lastPosition];
+ switch (currentByte)
+ {
+ case 0x20:
+ currentByte = 1;
+ break;
+ case 0x2D:
+ currentByte = 2;
+ break;
+ case 0xFF:
+ currentByte = 0xE;
+ break;
+ default:
+ currentByte -= 0x2C;
+ break;
+ }
+
+ if (currentByte == 0x00)
+ {
+ continue;
+ }
+
+ if (i % 2 == 0)
+ {
+ output.Add((byte)(currentByte << 4));
+ }
+ else
+ {
+ output[output.Count - 1] = (byte)(output.Last() | currentByte);
+ }
+ }
+ }
+
+ output.Add(0xFF);
+
+ sbyte sessionNumber = (sbyte)((EncryptionKey >> 6) & 0xFF & 0x80000003);
+
+ if (sessionNumber < 0)
+ {
+ sessionNumber = (sbyte)(((sessionNumber - 1) | 0xFFFFFFFC) + 1);
+ }
+
+ byte sessionKey = (byte)(EncryptionKey & 0xFF);
+
+ if (EncryptionKey != 0)
+ {
+ sessionNumber = -1;
+ }
+
+ switch (sessionNumber)
+ {
+ case 0:
+ for (int i = 0; i < output.Count; i++)
+ {
+ output[i] = (byte)(output[i] + sessionKey + 0x40);
+ }
+
+ break;
+ case 1:
+ for (int i = 0; i < output.Count; i++)
+ {
+ output[i] = (byte)(output[i] - (sessionKey + 0x40));
+ }
+
+ break;
+ case 2:
+ for (int i = 0; i < output.Count; i++)
+ {
+ output[i] = (byte)((output[i] ^ 0xC3) + sessionKey + 0x40);
+ }
+
+ break;
+ case 3:
+ for (int i = 0; i < output.Count; i++)
+ {
+ output[i] = (byte)((output[i] ^ 0xC3) - (sessionKey + 0x40));
+ }
+
+ break;
+ default:
+ for (int i = 0; i < output.Count; i++)
+ {
+ output[i] = (byte)(output[i] + 0x0F);
+ }
+
+ break;
+ }
+
+ return output.ToArray();
+ }
+}<
\ No newline at end of file
A Core/NosSmooth.Cryptography/CryptographyManager.cs => Core/NosSmooth.Cryptography/CryptographyManager.cs +57 -0
@@ 0,0 1,57 @@
+//
+// CryptographyManager.cs
+//
+// Copyright (c) František Boháček. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace NosSmooth.Cryptography;
+
+/// <summary>
+/// A storage of server and client cryptography.
+/// </summary>
+public class CryptographyManager
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CryptographyManager"/> class.
+ /// </summary>
+ public CryptographyManager()
+ {
+ ServerWorld = new ServerWorldCryptography(0);
+ ServerLogin = new ServerLoginCryptography();
+ ClientLogin = new ClientLoginCryptography();
+ ClientWorld = new ClientWorldCryptography(0);
+ }
+
+ /// <summary>
+ /// Gets the cryptography for server world.
+ /// </summary>
+ public ICryptography ServerWorld { get; }
+
+ /// <summary>
+ /// Gets the cryptography for server login.
+ /// </summary>
+ public ICryptography ServerLogin { get; }
+
+ /// <summary>
+ /// Gets the cryptography for client world.
+ /// </summary>
+ public ICryptography ClientWorld { get; }
+
+ /// <summary>
+ /// Gets the cryptography for client login.
+ /// </summary>
+ public ICryptography ClientLogin { get; }
+
+ /// <summary>
+ /// Gets or sets the encryption key of the connection.
+ /// </summary>
+ public int EncryptionKey
+ {
+ get => ((ServerWorldCryptography)ServerWorld).EncryptionKey;
+ set
+ {
+ ((ServerWorldCryptography)ServerWorld).EncryptionKey = value;
+ ((ClientWorldCryptography)ClientWorld).EncryptionKey = value;
+ }
+ }
+}<
\ No newline at end of file
A Core/NosSmooth.Cryptography/ICryptography.cs => Core/NosSmooth.Cryptography/ICryptography.cs +31 -0
@@ 0,0 1,31 @@
+//
+// ICryptography.cs
+//
+// Copyright (c) František Boháček. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Text;
+
+namespace NosSmooth.Cryptography;
+
+/// <summary>
+/// An intefrace for NosTale cryptography, encryption, decryption of packets.
+/// </summary>
+public interface ICryptography
+{
+ /// <summary>
+ /// Decrypt the raw packet (byte array) to a readable list string.
+ /// </summary>
+ /// <param name="str">Bytes to decrypt.</param>
+ /// <param name="encoding">The encoding.</param>
+ /// <returns>Decrypted packet to string list.</returns>
+ string Decrypt(in ReadOnlySpan<byte> str, Encoding encoding);
+
+ /// <summary>
+ /// Encrypt the string packet to byte array.
+ /// </summary>
+ /// <param name="packet">String to encrypt.</param>
+ /// <param name="encoding">The encoding.</param>
+ /// <returns>Encrypted packet as byte array.</returns>
+ byte[] Encrypt(string packet, Encoding encoding);
+}<
\ No newline at end of file
A Core/NosSmooth.Cryptography/NosSmooth.Cryptography.csproj => Core/NosSmooth.Cryptography/NosSmooth.Cryptography.csproj +9 -0
@@ 0,0 1,9 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net7.0</TargetFramework>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <Nullable>enable</Nullable>
+ </PropertyGroup>
+
+</Project>
A Core/NosSmooth.Cryptography/ServerLoginCryptography.cs => Core/NosSmooth.Cryptography/ServerLoginCryptography.cs +62 -0
@@ 0,0 1,62 @@
+//
+// ServerLoginCryptography.cs
+//
+// Copyright (c) František Boháček. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Text;
+
+namespace NosSmooth.Cryptography;
+
+/// <summary>
+/// A cryptography used for logging to NosTale server from the server.
+/// </summary>
+public class ServerLoginCryptography : ICryptography
+{
+ /// <inheritdoc />
+ public string Decrypt(in ReadOnlySpan<byte> str, Encoding encoding)
+ {
+ try
+ {
+ string decryptedPacket = string.Empty;
+
+ foreach (byte character in str)
+ {
+ if (character > 14)
+ {
+ decryptedPacket += Convert.ToChar((character - 15) ^ 195);
+ }
+ else
+ {
+ decryptedPacket += Convert.ToChar((256 - (15 - character)) ^ 195);
+ }
+ }
+
+ return decryptedPacket;
+ }
+ catch
+ {
+ return string.Empty;
+ }
+ }
+
+ /// <inheritdoc />
+ public byte[] Encrypt(string packet, Encoding encoding)
+ {
+ try
+ {
+ packet += " ";
+ byte[] tmp = Encoding.Default.GetBytes(packet);
+ for (int i = 0; i < packet.Length; i++)
+ {
+ tmp[i] = Convert.ToByte(tmp[i] + 15);
+ }
+ tmp[tmp.Length - 1] = 25;
+ return tmp;
+ }
+ catch
+ {
+ return Array.Empty<byte>();
+ }
+ }
+}<
\ No newline at end of file
A Core/NosSmooth.Cryptography/ServerWorldCryptography.cs => Core/NosSmooth.Cryptography/ServerWorldCryptography.cs +282 -0
@@ 0,0 1,282 @@
+//
+// ServerWorldCryptography.cs
+//
+// Copyright (c) František Boháček. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Text;
+
+namespace NosSmooth.Cryptography;
+
+/// <summary>
+/// A cryptography used on world server, has to have a session id (encryption key) set from the world.
+/// </summary>
+public class ServerWorldCryptography : ICryptography
+{
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ServerWorldCryptography"/> class.
+ /// </summary>
+ /// <param name="encryptionKey">The encryption key.</param>
+ public ServerWorldCryptography(int encryptionKey)
+ {
+ EncryptionKey = encryptionKey;
+ }
+
+ /// <summary>
+ /// Gets or sets the encryption key.
+ /// </summary>
+ public int EncryptionKey { get; set; }
+
+ /// <inheritdoc />
+ public string Decrypt(in ReadOnlySpan<byte> str, Encoding encoding)
+ {
+ if (EncryptionKey == 0)
+ {
+ return DecryptUnauthed(str);
+ }
+
+ return DecryptAuthed(str, EncryptionKey, encoding);
+ }
+
+ /// <inheritdoc />
+ public byte[] Encrypt(string packet, Encoding encoding)
+ {
+ byte[] strBytes = encoding.GetBytes(packet);
+ int bytesLength = strBytes.Length;
+
+ byte[] encryptedData = new byte[bytesLength + (int)Math.Ceiling((decimal)bytesLength / 0x7E) + 1];
+
+ int ii = 0;
+ for (int i = 0; i < bytesLength; i++)
+ {
+ if (i % 0x7E == 0)
+ {
+ encryptedData[i + ii] = (byte)(bytesLength - i > 0x7E ? 0x7E : bytesLength - i);
+ ii++;
+ }
+ encryptedData[i + ii] = (byte)~strBytes[i];
+ }
+ encryptedData[encryptedData.Length - 1] = 0xFF;
+
+ return encryptedData;
+ }
+
+ private static string DecryptAuthed(in ReadOnlySpan<byte> str, int encryptionKey, Encoding encoding)
+ {
+ var encryptedString = new StringBuilder();
+
+ int sessionKey = encryptionKey & 0xFF;
+ byte sessionNumber = unchecked((byte)(encryptionKey >> 6));
+ sessionNumber &= 0xFF;
+ sessionNumber &= 3;
+
+ switch (sessionNumber)
+ {
+ case 0:
+ foreach (byte character in str)
+ {
+ byte firstbyte = unchecked((byte)(sessionKey + 0x40));
+ byte highbyte = unchecked((byte)(character - firstbyte));
+ encryptedString.Append((char)highbyte);
+ }
+
+ break;
+
+ case 1:
+ foreach (byte character in str)
+ {
+ byte firstbyte = unchecked((byte)(sessionKey + 0x40));
+ byte highbyte = unchecked((byte)(character + firstbyte));
+ encryptedString.Append((char)highbyte);
+ }
+
+ break;
+
+ case 2:
+ foreach (byte character in str)
+ {
+ byte firstbyte = unchecked((byte)(sessionKey + 0x40));
+ byte highbyte = unchecked((byte)(character - firstbyte ^ 0xC3));
+ encryptedString.Append((char)highbyte);
+ }
+
+ break;
+
+ case 3:
+ foreach (byte character in str)
+ {
+ byte firstbyte = unchecked((byte)(sessionKey + 0x40));
+ byte highbyte = unchecked((byte)(character + firstbyte ^ 0xC3));
+ encryptedString.Append((char)highbyte);
+ }
+
+ break;
+
+ default:
+ encryptedString.Append((char)0xF);
+ break;
+ }
+
+ string[] temp = encryptedString.ToString().Split((char)0xFF);
+
+ var save = new StringBuilder();
+
+ for (int i = 0; i < temp.Length; i++)
+ {
+ save.Append(DecryptPrivate(temp[i].AsSpan(), encoding));
+ if (i < temp.Length - 2)
+ {
+ save.Append((char)'\n');
+ }
+ }
+
+ return save.ToString();
+ }
+
+ private static string DecryptPrivate(in ReadOnlySpan<char> str, Encoding encoding)
+ {
+ using var receiveData = new MemoryStream();
+ char[] table = { ' ', '-', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\n' };
+ for (int count = 0; count < str.Length; count++)
+ {
+ if (str[count] <= 0x7A)
+ {
+ int len = str[count];
+
+ for (int i = 0; i < len; i++)
+ {
+ count++;
+
+ try
+ {
+ receiveData.WriteByte(unchecked((byte)(str[count] ^ 0xFF)));
+ }
+ catch
+ {
+ receiveData.WriteByte(255);
+ }
+ }
+ }
+ else
+ {
+ int len = str[count];
+ len &= 0x7F;
+
+ for (int i = 0; i < len; i++)
+ {
+ count++;
+ int highbyte;
+ try
+ {
+ highbyte = str[count];
+ }
+ catch
+ {
+ highbyte = 0;
+ }
+
+ highbyte &= 0xF0;
+ highbyte >>= 0x4;
+
+ int lowbyte;
+ try
+ {
+ lowbyte = str[count];
+ }
+ catch
+ {
+ lowbyte = 0;
+ }
+
+ lowbyte &= 0x0F;
+
+ if (highbyte != 0x0 && highbyte != 0xF)
+ {
+ receiveData.WriteByte(unchecked((byte)table[highbyte - 1]));
+ i++;
+ }
+
+ if (lowbyte != 0x0 && lowbyte != 0xF)
+ {
+ receiveData.WriteByte(unchecked((byte)table[lowbyte - 1]));
+ }
+ }
+ }
+ }
+
+ byte[] tmp = Encoding.Convert(encoding, Encoding.UTF8, receiveData.ToArray());
+ return Encoding.UTF8.GetString(tmp);
+ }
+
+ private static string DecryptUnauthed(in ReadOnlySpan<byte> str)
+ {
+ try
+ {
+ var encryptedStringBuilder = new StringBuilder();
+ for (int i = 1; i < str.Length; i++)
+ {
+ if (Convert.ToChar(str[i]) == 0xE)
+ {
+ return encryptedStringBuilder.ToString();
+ }
+
+ int firstbyte = Convert.ToInt32(str[i] - 0xF);
+ int secondbyte = firstbyte;
+ secondbyte &= 240;
+ firstbyte = Convert.ToInt32(firstbyte - secondbyte);
+ secondbyte >>= 4;
+
+ switch (secondbyte)
+ {
+ case 0:
+ case 1:
+ encryptedStringBuilder.Append(' ');
+ break;
+
+ case 2:
+ encryptedStringBuilder.Append('-');
+ break;
+
+ case 3:
+ encryptedStringBuilder.Append('.');
+ break;
+
+ default:
+ secondbyte += 0x2C;
+ encryptedStringBuilder.Append(Convert.ToChar(secondbyte));
+ break;
+ }
+
+ switch (firstbyte)
+ {
+ case 0:
+ encryptedStringBuilder.Append(' ');
+ break;
+
+ case 1:
+ encryptedStringBuilder.Append(' ');
+ break;
+
+ case 2:
+ encryptedStringBuilder.Append('-');
+ break;
+
+ case 3:
+ encryptedStringBuilder.Append('.');
+ break;
+
+ default:
+ firstbyte += 0x2C;
+ encryptedStringBuilder.Append(Convert.ToChar(firstbyte));
+ break;
+ }
+ }
+
+ return encryptedStringBuilder.ToString();
+ }
+ catch (OverflowException)
+ {
+ return string.Empty;
+ }
+ }
+}<
\ No newline at end of file
M NosSmooth.sln => NosSmooth.sln +32 -0
@@ 54,6 54,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NosSmooth.Extensions.Pathfi
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NosSmooth.Game.Tests", "Tests\NosSmooth.Game.Tests\NosSmooth.Game.Tests.csproj", "{21ECBA0F-38FA-45A5-8B42-9A76425204BC}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NosSmooth.Cryptography", "Core\NosSmooth.Cryptography\NosSmooth.Cryptography.csproj", "{9035E5AD-8B5F-46CA-B8E1-5273722B392D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Pcap", "Pcap", "{B4224C41-FDB4-426A-83D8-C5AFB4F7D362}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NosSmooth.Pcap", "Pcap\NosSmooth.Pcap\NosSmooth.Pcap.csproj", "{FD185689-EE0F-4403-A1EB-5511D2292CF4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ 268,6 274,30 @@ Global
{21ECBA0F-38FA-45A5-8B42-9A76425204BC}.Release|x64.Build.0 = Release|Any CPU
{21ECBA0F-38FA-45A5-8B42-9A76425204BC}.Release|x86.ActiveCfg = Release|Any CPU
{21ECBA0F-38FA-45A5-8B42-9A76425204BC}.Release|x86.Build.0 = Release|Any CPU
+ {9035E5AD-8B5F-46CA-B8E1-5273722B392D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9035E5AD-8B5F-46CA-B8E1-5273722B392D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9035E5AD-8B5F-46CA-B8E1-5273722B392D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {9035E5AD-8B5F-46CA-B8E1-5273722B392D}.Debug|x64.Build.0 = Debug|Any CPU
+ {9035E5AD-8B5F-46CA-B8E1-5273722B392D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9035E5AD-8B5F-46CA-B8E1-5273722B392D}.Debug|x86.Build.0 = Debug|Any CPU
+ {9035E5AD-8B5F-46CA-B8E1-5273722B392D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9035E5AD-8B5F-46CA-B8E1-5273722B392D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9035E5AD-8B5F-46CA-B8E1-5273722B392D}.Release|x64.ActiveCfg = Release|Any CPU
+ {9035E5AD-8B5F-46CA-B8E1-5273722B392D}.Release|x64.Build.0 = Release|Any CPU
+ {9035E5AD-8B5F-46CA-B8E1-5273722B392D}.Release|x86.ActiveCfg = Release|Any CPU
+ {9035E5AD-8B5F-46CA-B8E1-5273722B392D}.Release|x86.Build.0 = Release|Any CPU
+ {FD185689-EE0F-4403-A1EB-5511D2292CF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FD185689-EE0F-4403-A1EB-5511D2292CF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FD185689-EE0F-4403-A1EB-5511D2292CF4}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {FD185689-EE0F-4403-A1EB-5511D2292CF4}.Debug|x64.Build.0 = Debug|Any CPU
+ {FD185689-EE0F-4403-A1EB-5511D2292CF4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FD185689-EE0F-4403-A1EB-5511D2292CF4}.Debug|x86.Build.0 = Debug|Any CPU
+ {FD185689-EE0F-4403-A1EB-5511D2292CF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FD185689-EE0F-4403-A1EB-5511D2292CF4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FD185689-EE0F-4403-A1EB-5511D2292CF4}.Release|x64.ActiveCfg = Release|Any CPU
+ {FD185689-EE0F-4403-A1EB-5511D2292CF4}.Release|x64.Build.0 = Release|Any CPU
+ {FD185689-EE0F-4403-A1EB-5511D2292CF4}.Release|x86.ActiveCfg = Release|Any CPU
+ {FD185689-EE0F-4403-A1EB-5511D2292CF4}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ 290,6 320,8 @@ Global
{21F7EA0B-5E3C-4016-8ADD-28AF37C00782} = {3A6D13E3-4BBA-4B3D-AE99-BAC8B375F7DF}
{564CAD6F-09B1-450B-83ED-9BCDE106B646} = {3A6D13E3-4BBA-4B3D-AE99-BAC8B375F7DF}
{21ECBA0F-38FA-45A5-8B42-9A76425204BC} = {C6A8760D-92CB-4307-88A7-36CCAEBA4AD1}
+ {9035E5AD-8B5F-46CA-B8E1-5273722B392D} = {01B5E872-271F-4D30-A1AA-AD48D81840C5}
+ {FD185689-EE0F-4403-A1EB-5511D2292CF4} = {B4224C41-FDB4-426A-83D8-C5AFB4F7D362}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C5F46653-4DEC-429B-8580-4ED18ED9B4CA}