Compare commits

39 Commits

Author SHA1 Message Date
733689cb5b Add SigFiles and Tests 2023-06-23 22:27:41 +02:00
25004cd83b Refactor readPacmanConfig
removed one indentation
2023-06-21 21:40:17 +02:00
42fe907ec8 Refactor readPacmanConfig
Reduced indentation && increased readability
2023-06-21 21:35:20 +02:00
6892191275 Use SonarQube
Used SonarQube to increase overall code quality
Files now live in their own directory
Fixed some tests
Added SonarQube directory to gitignore
2023-06-21 20:04:06 +02:00
58ceb31c1c Major changes
Now saving the ouput of the diff to a file in tmp
diff file can be loaded back into pacserver
Rewrote how checkIfDatabasesWereModified works
Slimmed down Program.cs to only have before and after
Add packages and databases into one list for transfer
2023-06-20 23:07:16 +02:00
15220e7135 Merge pull request 'Fix checkForNewerStuffTest' (#5) from fix/checkForNewerStuffTest into dev
Reviewed-on: #5
2023-06-19 22:37:06 +00:00
590b06fc86 Fix checkForNewerStuffTest
Fixed the tests that stopped working after refactoring #4
2023-06-20 00:35:31 +02:00
65b15f657d remove getDatabaseFromRegex 2023-06-19 22:37:52 +02:00
82a854dd8b refactor writeDatabaseAccessTimeToFile 2023-06-19 22:33:30 +02:00
5018856aab refactor writePackageNamesAndVersionToFile 2023-06-19 22:30:48 +02:00
dc811d7462 Merge pull request 'Major changes in package acquisition' (#4) from refactor/packageAcquisition into dev
Reviewed-on: #4
2023-06-18 20:55:56 +00:00
07982425e0 Write package name and version into text file 2023-06-18 22:55:15 +02:00
e609caf892 Major changes in package acquisition
This breaks a bunch of things that depended on the older version of this method
2023-06-18 22:44:43 +02:00
60dfb368e6 Merge pull request 'Use regex to filter databases' (#3) from feature/filterDatabasesForTransfer into dev
Reviewed-on: #3
2023-06-18 18:59:19 +00:00
41692548f2 Use regex to filter Databases 2023-06-18 20:46:43 +02:00
f923628c53 Merge pull request 'feature/checkForNewerPackagesAndDatabases' (#2) from feature/checkForNewerPackagesAndDatabases into dev
Reviewed-on: #2
2023-06-18 15:40:02 +00:00
1994e92e9e Minor changes && Add tests
Made a seperate method for writing the database access time files
Added tests for checkIfDatabasesWereModified
2023-06-18 17:24:56 +02:00
51aca7a2c2 Major advancements
Added a couple of test to check for acurate behavior in certain conditions
Added the capability to check if a database was modified
New commandline arguments
2023-06-17 02:47:35 +02:00
a1c1a0d5b0 Add fluentassertions test framework 2023-06-17 00:41:56 +02:00
422909352e Find new packages
We find new packages by getting the folder names in the DBPath local
2023-06-16 01:58:35 +02:00
a03dffabb7 Merge branch 'refactor' into dev 2023-06-15 20:24:56 +02:00
405b3580b6 Made justfile portable 2023-06-15 20:23:25 +02:00
013bc2fe33 Refactor pacserver 2023-06-12 02:19:07 +02:00
a9ac6d8bc2 Change to camelCase 2023-06-12 02:17:54 +02:00
88c6d7c284 Merge branch 'feature/TransferPacmanCache' into dev 2023-06-08 04:03:31 +02:00
7bbeaedf48 remove unneeded code 2023-06-06 21:26:56 +02:00
332ed62ca3 remove unused variables 2023-06-06 21:24:36 +02:00
205ef71dcd Implement TranserPacmanCache 2023-06-06 21:21:20 +02:00
a61c3fbfd9 Merge branch 'feature/determinePacmanDatabaseDirectory' into dev 2023-06-06 01:29:18 +02:00
3d512f25ab Add new recipe to justfile 2023-06-05 00:18:00 +02:00
4f474591da Add test for determinePacmanDatabaseDirectory 2023-06-04 23:15:16 +02:00
81fc8f1883 Implement determinePacmanDatabaseDirectory
Reused the code from determinePacmanCacheDirectory
2023-06-04 23:13:30 +02:00
89e79b1025 Change how commandline arguments are handled 2023-06-04 22:55:31 +02:00
35c6c5c8d9 Merge branch 'feature/unit-testing' into dev 2023-06-04 00:45:40 +02:00
9ad8012052 Major changes
Changed the whole project struture
justfile was adjusted to reflect the changes
Add Tests
Minor changes to .gitignore
2023-06-03 22:53:27 +02:00
10ba654b09 Add dotnet format to justfile 2023-06-03 14:55:11 +02:00
888df20cc9 Rework commandline arguments && Add Exceptions 2023-06-03 14:50:13 +02:00
04048c4cb9 Implement determinePacmanCacheDirectory
Used a StreamReader to read pacman.conf and then read one line until a line contains CacheDir
Then used a regex to only get the cache directory
2023-06-03 12:11:32 +02:00
20599a03ba Add justfile 2023-06-03 12:08:00 +02:00
16 changed files with 498 additions and 42 deletions

View File

@ -10,7 +10,7 @@ indent_style = space
tab_width = 4
# Naming Conventions
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
dotnet_naming_style.camel_case.capitalization = camel_case
# New line preferences
csharp_new_line_before_open_brace = none

5
.gitignore vendored
View File

@ -1,3 +1,4 @@
.vscode/
obj/
bin/
[Oo]bj/
[Bb]in/
.sonarqube/

View File

@ -1,16 +0,0 @@
public class Program {
static void Main(string[] args) {
if (args.Length == 0) {
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Please specify an option.");
Console.ResetColor();
} else {
switch (args[0]) {
case "":
break;
default:
break;
}
}
}
}

31
justfile Normal file
View File

@ -0,0 +1,31 @@
default:
@just --list
project_name := `printf '%s\n' "${PWD##*/}"`
uppercase_project_name := capitalize(project_name)
setup:
@dotnet new sln --name {{project_name}}
@mkdir src
@dotnet new classlib -o src/{{uppercase_project_name}}
@dotnet new xunit -o src/{{uppercase_project_name}}.Tests
@dotnet sln add src/{{uppercase_project_name}}/{{uppercase_project_name}}.csproj
@dotnet sln add src/{{uppercase_project_name}}.Tests/{{uppercase_project_name}}.Tests.csproj
@dotnet add src/{{uppercase_project_name}}/{{uppercase_project_name}}.csproj reference src/{{uppercase_project_name}}.Tests/{{uppercase_project_name}}.Tests.csproj
run:
@dotnet run
build:
@dotnet build src/{{uppercase_project_name}}/{{project_name}}.csproj
@dotnet build src/{{uppercase_project_name}}.Tests/{{uppercase_project_name}}.Tests.csproj
publish: format
@dotnet publish --configuration Release src/{{uppercase_project_name}}/{{project_name}}.csproj
format:
@dotnet format src/{{uppercase_project_name}}
@dotnet format src/{{uppercase_project_name}}.Tests
test: build
@dotnet test src/{{uppercase_project_name}}.Tests

View File

@ -1,23 +0,0 @@
public class Pacserver {
public static string pacmanCacheDirectory { get; set; } = string.Empty;
public static string determinePacmanCacheDirectory() {
return pacmanCacheDirectory;
}
public static string pacmanDatabaseDirectory { get; set; } = string.Empty;
public static string determinePacmanDatabaseDirectory() {
return pacmanDatabaseDirectory;
}
public static void checkForNewerPackagesAndDatabases() {
}
public static void transferPacmanCache() {
}
public static void transferPacmanDatabases() {
}
}

View File

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Pacserver\pacserver.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,18 @@
using Pacserver.Utils;
namespace Pacserver.Tests;
public class TranserFilesTest {
[Fact]
public async void transferPacmanCache_doesNotFail() {
// Arrange
PacserverUtils utils = new PacserverUtils();
// Act
utils.readPacmanConfig();
Action act = () => utils.transfer();
// Assert
act.Should().NotThrow();
}
}

View File

@ -0,0 +1,2 @@
global using Xunit;
global using FluentAssertions;

View File

@ -0,0 +1,62 @@
using Pacserver.Utils;
namespace Pacserver.Tests;
public class checkForNewerStuffTest {
[Fact]
public void checkForNewerPackages_throwsExceptionIfNoFilesExist() {
// Arrange
PacserverUtils utils = new PacserverUtils();
File.Delete(utils.pacserverDirectory + "packages_before.txt");
File.Delete(utils.pacserverDirectory + "packages_after.txt");
// Act
Action act = () => utils.diff(utils.pacserverDirectory + "packages_before.txt", utils.pacserverDirectory + "packages_after.txt");
// Assert
act.Should().Throw<FileNotFoundException>().WithMessage("Necessary files could not be found");
}
[Fact]
public void getEveryPackageNameAndVersionViaFolderName_createsFiles() {
// Arrange
PacserverUtils utils = new PacserverUtils();
Directory.CreateDirectory("/tmp/pacserverTest/");
utils.pacmanCacheDirectory = "/tmp/pacserverTest/";
// Act
utils.getEveryPackageNameAndVersion("before", utils.pacserverDirectory + "packages_before.txt");
utils.getEveryPackageNameAndVersion("after", utils.pacserverDirectory + "packages_after.txt");
// Assert
File.Exists(utils.pacserverDirectory + "packages_before.txt").Should().BeTrue();
File.Exists(utils.pacserverDirectory + "packages_before.txt").Should().BeTrue();
}
[Fact]
public void packageNamesAndVersion_isEmpty() {
// Arrange
PacserverUtils utils = new PacserverUtils();
Directory.CreateDirectory("/tmp/pacserverTest/");
utils.pacmanCacheDirectory = "/tmp/pacserverTest/";
utils.getEveryPackageNameAndVersion("before", utils.pacserverDirectory + "packages_before.txt");
// Act
var packageList = utils.packageNamesAndVersion;
// Assert
packageList.Should().BeEmpty();
}
[Fact]
public void getEveryPackageNameAndVersionViaFolderName_throwsExceptionIfModeIsNotValid() {
// Arrange
PacserverUtils utils = new PacserverUtils();
// Act
Action act = () => utils.getEveryPackageNameAndVersion("test", utils.pacserverDirectory + "test.txt");
// Assert
act.Should().Throw<ArgumentException>().WithMessage("No valid mode was given. Valid modes are before and after");
}
}

View File

@ -0,0 +1,31 @@
using Pacserver.Utils;
namespace Pacserver.Tests;
public class checkIfDatabasesWereModifiedTest {
[Fact]
public void checkIfDatabasesWereModified_throwsExceptionIfNoValidModeIsGiven() {
// Arrange
PacserverUtils utils = new PacserverUtils();
utils.readPacmanConfig();
// Act
Action act = () => utils.checkIfDatabasesWereModified("test", "/tmp/test.txt");
// Assert
act.Should().Throw<ArgumentException>().WithMessage("No valid mode was given. Valid modes are before and after");
}
[Fact]
public void checkIfDatabasesWereModified_throwsNoExceptionIfValidModeIsGiven() {
// Arrange
PacserverUtils utils = new PacserverUtils();
utils.readPacmanConfig();
// Act
Action act = () => utils.checkIfDatabasesWereModified("before", "/tmp/test.txt");
// Assert
act.Should().NotThrow();
}
}

View File

@ -0,0 +1,22 @@
using Pacserver.Utils;
namespace Pacserver.Tests;
public class getEverySigFileTest {
[Fact]
public void getEverySigFile_ListShouldNotBeEmpty() {
// Arrange
PacserverUtils utils = new PacserverUtils();
Directory.CreateDirectory("/tmp/pacserverTest/");
utils.pacmanCacheDirectory = "/tmp/pacserverTest/";
File.Create(utils.pacmanCacheDirectory + "zsh-5.9-3-x86_64.pkg.tar.zst.sig");
// Act
utils.getEverySigFile();
var sigFiles = utils.sigFiles;
Directory.Delete(utils.pacmanCacheDirectory, true);
// Assert
sigFiles.Should().NotBeEmpty();
}
}

View File

@ -0,0 +1,18 @@
using Pacserver.Utils;
namespace Pacserver.Tests;
public class readPacmanConfigTest {
[Fact]
public void readPacmanConfig_returnsNoException() {
// Arrange
PacserverUtils utils = new PacserverUtils();
// Act
var exception = Record.Exception(() => utils.readPacmanConfig());
// Assert
Assert.Null(exception);
}
}

197
src/Pacserver/Pacserver.cs Normal file
View File

@ -0,0 +1,197 @@
using System.Collections.Immutable;
using System.Text.RegularExpressions;
namespace Pacserver.Utils;
public partial class PacserverUtils {
public string? pacserverDirectory { get; set; }
public void prerequisites() {
AppDomain.CurrentDomain.SetData("REGEX_DEFAULT_MATCH_TIMEOUT", TimeSpan.FromMilliseconds(100));
pacserverDirectory = "/tmp/pacserver/";
pacmanCacheDirectory = string.Empty;
pacmanDatabaseDirectory = string.Empty;
if (!Directory.Exists(pacserverDirectory)) {
Directory.CreateDirectory(pacserverDirectory);
}
}
public void cleanup() {
if (Directory.Exists(pacserverDirectory)) {
Directory.Delete(pacserverDirectory, true);
}
}
public string? pacmanCacheDirectory { get; set; }
public string? pacmanDatabaseDirectory { get; set; }
public readonly ImmutableList<String> pathsToDetermine = ImmutableList.Create("CacheDir", "DBPath");
[GeneratedRegex(@"\/(?:[\w.-]+\/)*[\w.-]+(?:\.\w+)*\/?$", RegexOptions.NonBacktracking)] // https://regex101.com/r/GwWeui/2
private static partial Regex CacheDirOrDBPathRegex();
public void readPacmanConfig() {
using (StreamReader file = new StreamReader("/etc/pacman.conf")) {
string? line;
while ((line = file.ReadLine()) is not null) {
string cachePath = pathsToDetermine[0];
string dbPath = pathsToDetermine[1];
if (!line.Contains(cachePath) && !line.Contains(dbPath)) {
continue;
}
Match match = CacheDirOrDBPathRegex().Match(line);
if (!match.Success) {
string pathsToDetermineString = string.Join(",", pathsToDetermine);
throw new DirectoryNotFoundException("Could not determine the necessary file paths: " + pathsToDetermineString);
}
if (line.Contains(cachePath)) {
pacmanCacheDirectory = match.ToString();
} else if (line.Contains(dbPath)) {
pacmanDatabaseDirectory = match.ToString();
}
}
}
}
public List<String> packageNamesAndVersion = new List<String>();
[GeneratedRegex(@".+\.pkg\.tar\.zst$", RegexOptions.NonBacktracking)]
private static partial Regex onlyGetPackages();
public void getEveryPackageNameAndVersion(string mode, string filePath) {
if (Directory.Exists(pacmanCacheDirectory)) {
if (Directory.GetFiles(pacmanCacheDirectory) is not null) {
packageNamesAndVersion = Directory.GetFiles(pacmanCacheDirectory).Where(file => onlyGetPackages().IsMatch(file)).ToList();
} else {
Console.WriteLine("No packages found in pacman cache");
}
} else {
Console.WriteLine("No pacman cache directory found");
}
switch (mode) {
case "before":
writePackageNamesAndVersionToFile(filePath);
break;
case "after":
writePackageNamesAndVersionToFile(filePath);
break;
default:
throw new ArgumentException("No valid mode was given. Valid modes are before and after");
}
}
public void writePackageNamesAndVersionToFile(string filePath) {
if (File.Exists(filePath)) {
File.Delete(filePath);
}
using (File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite)) {
using (StreamWriter sw = new StreamWriter(filePath)) {
foreach (string package in packageNamesAndVersion) {
sw.WriteLine(package);
}
}
}
}
public List<String> sigFiles = new List<String>();
[GeneratedRegex(@".+\.pkg\.tar\.zst\.sig$", RegexOptions.NonBacktracking)]
private static partial Regex onlyGetSigFiles();
public void getEverySigFile() {
if (Directory.Exists(pacmanCacheDirectory)) {
if (Directory.GetFiles(pacmanCacheDirectory) is not null) {
sigFiles = Directory.GetFiles(pacmanCacheDirectory).Where(file => onlyGetSigFiles().IsMatch(file)).ToList();
}
}
}
public List<String> diffOfPackagesOrDatabases = new List<String>();
public void diff(string before, string after) {
if (File.Exists(before) && File.Exists(after)) {
diffOfPackagesOrDatabases = File.ReadAllLines(after).Except(File.ReadLines(before)).ToList();
} else {
throw new FileNotFoundException("Necessary files could not be found");
}
}
public void saveDiffToFile(string filePath) {
if (File.Exists(filePath)) {
File.Delete(filePath);
}
using (File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite)) {
using (StreamWriter sw = new StreamWriter(filePath)) {
foreach (string packageOrDatabase in diffOfPackagesOrDatabases) {
sw.WriteLine(packageOrDatabase);
}
}
}
}
public List<String> readDiffFileToList(string filePath) {
using (File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) {
return File.ReadAllLines(filePath).ToList();
}
}
public List<String> databases = new List<String>();
public void checkIfDatabasesWereModified(string mode, string filePath) {
databases = Directory.GetFiles(pacmanDatabaseDirectory + "sync/").ToList();
switch (mode) {
case "before":
writeDatabaseAccessTimeToFile(filePath);
break;
case "after":
writeDatabaseAccessTimeToFile(filePath);
break;
default:
throw new ArgumentException("No valid mode was given. Valid modes are before and after");
}
}
public void writeDatabaseAccessTimeToFile(string filePath) {
if (File.Exists(filePath)) {
File.Delete(filePath);
}
using (File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read)) {
using (StreamWriter sw = new StreamWriter(filePath)) {
foreach (string database in databases) {
sw.WriteLine(database + " " + File.GetLastAccessTime(database));
}
}
}
}
public List<String> databasesToTransfer = new List<String>();
[GeneratedRegex(@"\/(?:[\w.-]+\/)*[\w.-]+(?:\.\w+)*\/*db", RegexOptions.NonBacktracking)] // https://regex101.com/r/Wm5M0P/1
private static partial Regex onlyGetDatabaseName();
public void filterDiffOutputForDatabases() {
foreach (string database in diffOfPackagesOrDatabases) {
databasesToTransfer.Add(onlyGetDatabaseName().Match(database).Value);
}
}
private static List<String> newerPackagesAndDatabases = new List<String>();
public void combinePackagesWithDatabases() {
newerPackagesAndDatabases.AddRange(packageNamesAndVersion);
newerPackagesAndDatabases.AddRange(databasesToTransfer);
newerPackagesAndDatabases.AddRange(sigFiles);
}
public async Task transfer() {
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://192.168.0.69:12000/upload?path=/");
MultipartFormDataContent content = new MultipartFormDataContent();
foreach (string pkgOrDb in newerPackagesAndDatabases) {
content.Add(new ByteArrayContent(File.ReadAllBytes(pacmanCacheDirectory + pkgOrDb)), "path", Path.GetFileName(pacmanCacheDirectory + pkgOrDb));
}
request.Content = content;
await client.SendAsync(request);
}
}

52
src/Pacserver/Program.cs Normal file
View File

@ -0,0 +1,52 @@
using Pacserver.Utils;
public class Program {
protected Program() {
}
static void Main(string[] args) {
if (args.Length == 0) {
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Please specify an option.");
Console.ResetColor();
Console.WriteLine("Possible options are: before, after");
return;
}
PacserverUtils utils = new PacserverUtils();
utils.prerequisites();
utils.readPacmanConfig();
switch (args[0]) {
case "before":
utils.getEveryPackageNameAndVersion("before", utils.pacserverDirectory + "packages_before.txt");
utils.checkIfDatabasesWereModified("before", utils.pacserverDirectory + "databases_before.txt");
break;
case "after":
utils.getEveryPackageNameAndVersion("after", utils.pacserverDirectory + "packages_after.txt");
utils.checkIfDatabasesWereModified("after", utils.pacserverDirectory + "databases_after.txt");
utils.diff(utils.pacserverDirectory + "packages_before.txt", utils.pacserverDirectory + "packages_after.txt");
utils.saveDiffToFile(utils.pacserverDirectory + "package_diff.txt");
utils.diff(utils.pacserverDirectory + "databases_before.txt", utils.pacserverDirectory + "databases_after.txt");
utils.saveDiffToFile(utils.pacserverDirectory + "database_diff.txt");
utils.filterDiffOutputForDatabases();
utils.packageNamesAndVersion = utils.readDiffFileToList(utils.pacserverDirectory + "package_diff.txt");
utils.getEverySigFile();
utils.combinePackagesWithDatabases();
utils.transfer();
utils.cleanup();
break;
default:
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(args[0] + " is not a recognized option.");
Console.ResetColor();
Console.WriteLine("Possible options are: before, after");
break;
}
}
}

32
src/pacserver.sln Normal file
View File

@ -0,0 +1,32 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "pacserver", "Pacserver\pacserver.csproj", "{2B605458-AFBE-4A78-B4EA-9562C82BC932}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pacserver.Tests", "Pacserver.Tests\Pacserver.Tests.csproj", "{0B504958-E66D-4E32-AB22-19F94713AFCD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6FCF1241-CE3C-4A4A-8625-866A4E8E7623}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FCF1241-CE3C-4A4A-8625-866A4E8E7623}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FCF1241-CE3C-4A4A-8625-866A4E8E7623}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FCF1241-CE3C-4A4A-8625-866A4E8E7623}.Release|Any CPU.Build.0 = Release|Any CPU
{2B605458-AFBE-4A78-B4EA-9562C82BC932}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2B605458-AFBE-4A78-B4EA-9562C82BC932}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2B605458-AFBE-4A78-B4EA-9562C82BC932}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B605458-AFBE-4A78-B4EA-9562C82BC932}.Release|Any CPU.Build.0 = Release|Any CPU
{0B504958-E66D-4E32-AB22-19F94713AFCD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0B504958-E66D-4E32-AB22-19F94713AFCD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B504958-E66D-4E32-AB22-19F94713AFCD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B504958-E66D-4E32-AB22-19F94713AFCD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal