diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj
index ce2eaaf18..f30f7879f 100644
--- a/src/Artemis.UI/Artemis.UI.csproj
+++ b/src/Artemis.UI/Artemis.UI.csproj
@@ -12,6 +12,7 @@
+
diff --git a/src/Artemis.UI/ArtemisBootstrapper.cs b/src/Artemis.UI/ArtemisBootstrapper.cs
index 52cab9df9..dbed7a0f4 100644
--- a/src/Artemis.UI/ArtemisBootstrapper.cs
+++ b/src/Artemis.UI/ArtemisBootstrapper.cs
@@ -12,6 +12,7 @@ using Artemis.UI.Shared.DryIoc;
using Artemis.UI.Shared.Services;
using Artemis.VisualScripting.DryIoc;
using Artemis.WebClient.Updating.DryIoc;
+using Artemis.WebClient.Workshop.DryIoc;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
@@ -45,6 +46,7 @@ public static class ArtemisBootstrapper
_container.RegisterUI();
_container.RegisterSharedUI();
_container.RegisterUpdatingClient();
+ _container.RegisterWorkshopClient();
_container.RegisterNoStringEvaluating();
configureServices?.Invoke(_container);
diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml b/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml
index 4cd4ef63f..485e308ca 100644
--- a/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml
+++ b/src/Artemis.UI/Screens/Workshop/WorkshopView.axaml
@@ -10,62 +10,26 @@
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
xmlns:gradientPicker="clr-namespace:Artemis.UI.Shared.Controls.GradientPicker;assembly=Artemis.UI.Shared"
xmlns:materialIconPicker="clr-namespace:Artemis.UI.Shared.MaterialIconPicker;assembly=Artemis.UI.Shared"
+ xmlns:workshop1="clr-namespace:Artemis.WebClient.Workshop;assembly=Artemis.WebClient.Workshop"
mc:Ignorable="d" d:DesignWidth="800"
x:Class="Artemis.UI.Screens.Workshop.WorkshopView"
x:DataType="workshop:WorkshopViewModel">
-
-
-
-
- Notification tests
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs b/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs
index 32df9585c..44fbb4226 100644
--- a/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs
+++ b/src/Artemis.UI/Screens/Workshop/WorkshopViewModel.cs
@@ -1,70 +1,52 @@
-using System.Reactive;
+using System;
+using System.Collections.ObjectModel;
+using System.Reactive;
using System.Reactive.Linq;
+using System.Threading.Tasks;
using Artemis.Core;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Builders;
+using Artemis.WebClient.Workshop;
using Avalonia.Input;
using ReactiveUI;
using SkiaSharp;
+using StrawberryShake;
namespace Artemis.UI.Screens.Workshop;
public class WorkshopViewModel : MainScreenViewModel
{
- private readonly ObservableAsPropertyHelper _cursor;
- private readonly INotificationService _notificationService;
+ private readonly IWorkshopClient _workshopClient;
- private ColorGradient _colorGradient = new()
+ public WorkshopViewModel(IScreen hostScreen, IWorkshopClient workshopClient) : base(hostScreen, "workshop")
{
- new ColorGradientStop(new SKColor(0xFFFF6D00), 0f),
- new ColorGradientStop(new SKColor(0xFFFE6806), 0.2f),
- new ColorGradientStop(new SKColor(0xFFEF1788), 0.4f),
- new ColorGradientStop(new SKColor(0xFFEF1788), 0.6f),
- new ColorGradientStop(new SKColor(0xFF00FCCC), 0.8f),
- new ColorGradientStop(new SKColor(0xFF00FCCC), 1f)
- };
-
- private StandardCursorType _selectedCursor;
- private double _testValue;
-
- public WorkshopViewModel(IScreen hostScreen, INotificationService notificationService) : base(hostScreen, "workshop")
- {
- _notificationService = notificationService;
- _cursor = this.WhenAnyValue(vm => vm.SelectedCursor).Select(c => new Cursor(c)).ToProperty(this, vm => vm.Cursor);
-
+ _workshopClient = workshopClient;
DisplayName = "Workshop";
- ShowNotification = ReactiveCommand.Create(ExecuteShowNotification);
+
+ Task.Run(() => GetEntries());
}
- public ReactiveCommand ShowNotification { get; set; }
+ public ObservableCollection Test { get; set; } = new();
- public StandardCursorType SelectedCursor
+ private async Task GetEntries()
{
- get => _selectedCursor;
- set => RaiseAndSetIfChanged(ref _selectedCursor, value);
- }
- public Cursor Cursor => _cursor.Value;
-
- public ColorGradient ColorGradient
- {
- get => _colorGradient;
- set => RaiseAndSetIfChanged(ref _colorGradient, value);
- }
-
- public double TestValue
- {
- get => _testValue;
- set => RaiseAndSetIfChanged(ref _testValue, value);
- }
-
- public void CreateRandomGradient()
- {
- ColorGradient = ColorGradient.GetRandom(6);
- }
-
- private void ExecuteShowNotification(NotificationSeverity severity)
- {
- _notificationService.CreateNotification().WithTitle("Test title").WithMessage("Test message").WithSeverity(severity).Show();
+ try
+ {
+ IOperationResult entries = await _workshopClient.GetEntries.ExecuteAsync();
+ if (entries.Data?.Entries?.Nodes == null)
+ return;
+
+ foreach (IGetEntries_Entries_Nodes getEntriesEntriesNodes in entries.Data.Entries.Nodes)
+ {
+ Console.WriteLine(getEntriesEntriesNodes);
+ Test.Add(getEntriesEntriesNodes);
+ }
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ throw;
+ }
}
}
\ No newline at end of file
diff --git a/src/Artemis.WebClient.Updating/.graphqlconfig b/src/Artemis.WebClient.Updating/.graphqlconfig
deleted file mode 100644
index 727ec86a0..000000000
--- a/src/Artemis.WebClient.Updating/.graphqlconfig
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "Untitled GraphQL Schema",
- "schemaPath": "schema.graphql",
- "extensions": {
- "endpoints": {
- "Default GraphQL Endpoint": {
- "url": "https://updating.artemis-rgb.com/graphql",
- "headers": {
- "user-agent": "JS GraphQL"
- },
- "introspect": true
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/Artemis.WebClient.Updating/Artemis.WebClient.Updating.csproj b/src/Artemis.WebClient.Updating/Artemis.WebClient.Updating.csproj
index c31da3c25..0b6943ddc 100644
--- a/src/Artemis.WebClient.Updating/Artemis.WebClient.Updating.csproj
+++ b/src/Artemis.WebClient.Updating/Artemis.WebClient.Updating.csproj
@@ -13,4 +13,8 @@
+
+
+
+
diff --git a/src/Artemis.WebClient.Updating/graphql.config.yml b/src/Artemis.WebClient.Updating/graphql.config.yml
new file mode 100644
index 000000000..784e49e2e
--- /dev/null
+++ b/src/Artemis.WebClient.Updating/graphql.config.yml
@@ -0,0 +1,8 @@
+schema: schema.graphql
+extensions:
+ endpoints:
+ Default GraphQL Endpoint:
+ url: https://updating.artemis-rgb.com/graphql
+ headers:
+ user-agent: JS GraphQL
+ introspect: true
diff --git a/src/Artemis.WebClient.Updating/schema.extensions.graphql b/src/Artemis.WebClient.Updating/schema.extensions.graphql
deleted file mode 100644
index 0b5fbd98b..000000000
--- a/src/Artemis.WebClient.Updating/schema.extensions.graphql
+++ /dev/null
@@ -1,13 +0,0 @@
-scalar _KeyFieldSet
-
-directive @key(fields: _KeyFieldSet!) on SCHEMA | OBJECT
-
-directive @serializationType(name: String!) on SCALAR
-
-directive @runtimeType(name: String!) on SCALAR
-
-directive @enumValue(value: String!) on ENUM_VALUE
-
-directive @rename(name: String!) on INPUT_FIELD_DEFINITION | INPUT_OBJECT | ENUM | ENUM_VALUE
-
-extend schema @key(fields: "id")
\ No newline at end of file
diff --git a/src/Artemis.WebClient.Updating/schema.graphql b/src/Artemis.WebClient.Updating/schema.graphql
index fe855cb6c..c0973062b 100644
--- a/src/Artemis.WebClient.Updating/schema.graphql
+++ b/src/Artemis.WebClient.Updating/schema.graphql
@@ -1,4 +1,4 @@
-# This file was generated based on ".graphqlconfig". Do not edit manually.
+# This file was generated. Do not edit manually.
schema {
query: Query
@@ -107,10 +107,11 @@ type Release {
type ReleaseStatistic {
count: Int!
+ date: Date!
lastReportedUsage: DateTime!
linuxCount: Int!
osxCount: Int!
- releaseId: UUID!
+ release: Release
windowsCount: Int!
}
@@ -144,6 +145,9 @@ enum SortEnumType {
DESC
}
+"The `Date` scalar represents an ISO-8601 compliant date type."
+scalar Date
+
"The `DateTime` scalar represents an ISO-8601 compliant date time type."
scalar DateTime
@@ -176,6 +180,21 @@ input BooleanOperationFilterInput {
neq: Boolean
}
+input DateOperationFilterInput {
+ eq: Date
+ gt: Date
+ gte: Date
+ in: [Date]
+ lt: Date
+ lte: Date
+ neq: Date
+ ngt: Date
+ ngte: Date
+ nin: [Date]
+ nlt: Date
+ nlte: Date
+}
+
input DateTimeOperationFilterInput {
eq: DateTime
gt: DateTime
@@ -265,20 +284,22 @@ input ReleaseSortInput {
input ReleaseStatisticFilterInput {
and: [ReleaseStatisticFilterInput!]
count: IntOperationFilterInput
+ date: DateOperationFilterInput
lastReportedUsage: DateTimeOperationFilterInput
linuxCount: IntOperationFilterInput
or: [ReleaseStatisticFilterInput!]
osxCount: IntOperationFilterInput
- releaseId: UuidOperationFilterInput
+ release: ReleaseFilterInput
windowsCount: IntOperationFilterInput
}
input ReleaseStatisticSortInput {
count: SortEnumType
+ date: SortEnumType
lastReportedUsage: SortEnumType
linuxCount: SortEnumType
osxCount: SortEnumType
- releaseId: SortEnumType
+ release: ReleaseSortInput
windowsCount: SortEnumType
}
diff --git a/src/Artemis.WebClient.Workshop/.config/dotnet-tools.json b/src/Artemis.WebClient.Workshop/.config/dotnet-tools.json
new file mode 100644
index 000000000..7d8626c03
--- /dev/null
+++ b/src/Artemis.WebClient.Workshop/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "strawberryshake.tools": {
+ "version": "13.0.0-rc.4",
+ "commands": [
+ "dotnet-graphql"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.WebClient.Workshop/.graphqlrc.json b/src/Artemis.WebClient.Workshop/.graphqlrc.json
new file mode 100644
index 000000000..24fb39de3
--- /dev/null
+++ b/src/Artemis.WebClient.Workshop/.graphqlrc.json
@@ -0,0 +1,22 @@
+{
+ "schema": "schema.graphql",
+ "documents": "**/*.graphql",
+ "extensions": {
+ "strawberryShake": {
+ "name": "WorkshopClient",
+ "namespace": "Artemis.WebClient.Workshop",
+ "url": "https://localhost:7281/graphql/",
+ "emitGeneratedCode": false,
+ "records": {
+ "inputs": false,
+ "entities": false
+ },
+ "transportProfiles": [
+ {
+ "default": "Http",
+ "subscription": "WebSocket"
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj
new file mode 100644
index 000000000..0b6943ddc
--- /dev/null
+++ b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs b/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs
new file mode 100644
index 000000000..aed1df5a7
--- /dev/null
+++ b/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs
@@ -0,0 +1,26 @@
+using DryIoc;
+using DryIoc.Microsoft.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Artemis.WebClient.Workshop.DryIoc;
+
+///
+/// Provides an extension method to register services onto a DryIoc .
+///
+public static class ContainerExtensions
+{
+ ///
+ /// Registers the updating client into the container.
+ ///
+ /// The builder building the current container
+ public static void RegisterWorkshopClient(this IContainer container)
+ {
+ ServiceCollection serviceCollection = new();
+ serviceCollection
+ .AddHttpClient()
+ .AddWorkshopClient()
+ .ConfigureHttpClient(client => client.BaseAddress = new Uri("https://localhost:7281/graphql"));
+
+ container.WithDependencyInjectionAdapter(serviceCollection);
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql b/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql
new file mode 100644
index 000000000..9d9457e62
--- /dev/null
+++ b/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql
@@ -0,0 +1,9 @@
+query GetEntries {
+ entries {
+ nodes {
+ author
+ name
+ entryType
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.WebClient.Workshop/Queries/GetEntryById.graphql b/src/Artemis.WebClient.Workshop/Queries/GetEntryById.graphql
new file mode 100644
index 000000000..e5ba4a96d
--- /dev/null
+++ b/src/Artemis.WebClient.Workshop/Queries/GetEntryById.graphql
@@ -0,0 +1,7 @@
+query GetEntryById($id: UUID!) {
+ entry(id: $id) {
+ author
+ name
+ entryType
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.WebClient.Workshop/graphql.config.yml b/src/Artemis.WebClient.Workshop/graphql.config.yml
new file mode 100644
index 000000000..a8ba99703
--- /dev/null
+++ b/src/Artemis.WebClient.Workshop/graphql.config.yml
@@ -0,0 +1,8 @@
+schema: schema.graphql
+extensions:
+ endpoints:
+ Default GraphQL Endpoint:
+ url: https://localhost:7281/graphql
+ headers:
+ user-agent: JS GraphQL
+ introspect: true
diff --git a/src/Artemis.WebClient.Workshop/schema.graphql b/src/Artemis.WebClient.Workshop/schema.graphql
new file mode 100644
index 000000000..daa53bde8
--- /dev/null
+++ b/src/Artemis.WebClient.Workshop/schema.graphql
@@ -0,0 +1,244 @@
+# This file was generated. Do not edit manually.
+
+schema {
+ query: Query
+ mutation: Mutation
+}
+
+"A connection to a list of items."
+type EntriesConnection {
+ "A list of edges."
+ edges: [EntriesEdge!]
+ "A flattened list of the nodes."
+ nodes: [Entry!]
+ "Information to aid in pagination."
+ pageInfo: PageInfo!
+ "Identifies the total count of items in the connection."
+ totalCount: Int!
+}
+
+"An edge in a connection."
+type EntriesEdge {
+ "A cursor for use in pagination."
+ cursor: String!
+ "The item at the end of the edge."
+ node: Entry!
+}
+
+type Entry {
+ author: UUID!
+ description: String!
+ entryType: EntryType!
+ icon: Image
+ id: UUID!
+ images: [Image!]!
+ name: String!
+ releases: [Release!]!
+ tags: [String!]!
+}
+
+type Image {
+ id: UUID!
+ mimeType: String!
+}
+
+type Mutation {
+ addEntry(input: EntryInput!): Entry
+}
+
+"Information about pagination in a connection."
+type PageInfo {
+ "When paginating forwards, the cursor to continue."
+ endCursor: String
+ "Indicates whether more edges exist following the set defined by the clients arguments."
+ hasNextPage: Boolean!
+ "Indicates whether more edges exist prior the set defined by the clients arguments."
+ hasPreviousPage: Boolean!
+ "When paginating backwards, the cursor to continue."
+ startCursor: String
+}
+
+type Query {
+ entries(
+ "Returns the elements in the list that come after the specified cursor."
+ after: String,
+ "Returns the elements in the list that come before the specified cursor."
+ before: String,
+ "Returns the first _n_ elements from the list."
+ first: Int,
+ "Returns the last _n_ elements from the list."
+ last: Int,
+ order: [EntrySortInput!],
+ where: EntryFilterInput
+ ): EntriesConnection
+ entry(id: UUID!): Entry
+}
+
+type Release {
+ createdAt: DateTime!
+ downloadSize: Long!
+ downloads: Long!
+ id: UUID!
+ md5Hash: String
+ version: String!
+}
+
+enum EntryType {
+ LAYOUT
+ PLUGIN
+ PROFILE
+}
+
+enum SortEnumType {
+ ASC
+ DESC
+}
+
+"The `DateTime` scalar represents an ISO-8601 compliant date time type."
+scalar DateTime
+
+"The `Long` scalar type represents non-fractional signed whole 64-bit numeric values. Long can represent values between -(2^63) and 2^63 - 1."
+scalar Long
+
+scalar UUID
+
+input DateTimeOperationFilterInput {
+ eq: DateTime
+ gt: DateTime
+ gte: DateTime
+ in: [DateTime]
+ lt: DateTime
+ lte: DateTime
+ neq: DateTime
+ ngt: DateTime
+ ngte: DateTime
+ nin: [DateTime]
+ nlt: DateTime
+ nlte: DateTime
+}
+
+input EntryFilterInput {
+ and: [EntryFilterInput!]
+ author: UuidOperationFilterInput
+ description: StringOperationFilterInput
+ entryType: EntryTypeOperationFilterInput
+ icon: ImageFilterInput
+ id: UuidOperationFilterInput
+ images: ListFilterInputTypeOfImageFilterInput
+ name: StringOperationFilterInput
+ or: [EntryFilterInput!]
+ releases: ListFilterInputTypeOfReleaseFilterInput
+ tags: ListStringOperationFilterInput
+}
+
+input EntryInput {
+ description: String!
+ entryType: EntryType!
+ name: String!
+ tags: [String!]!
+}
+
+input EntrySortInput {
+ author: SortEnumType
+ description: SortEnumType
+ entryType: SortEnumType
+ icon: ImageSortInput
+ id: SortEnumType
+ name: SortEnumType
+}
+
+input EntryTypeOperationFilterInput {
+ eq: EntryType
+ in: [EntryType!]
+ neq: EntryType
+ nin: [EntryType!]
+}
+
+input ImageFilterInput {
+ and: [ImageFilterInput!]
+ id: UuidOperationFilterInput
+ mimeType: StringOperationFilterInput
+ or: [ImageFilterInput!]
+}
+
+input ImageSortInput {
+ id: SortEnumType
+ mimeType: SortEnumType
+}
+
+input ListFilterInputTypeOfImageFilterInput {
+ all: ImageFilterInput
+ any: Boolean
+ none: ImageFilterInput
+ some: ImageFilterInput
+}
+
+input ListFilterInputTypeOfReleaseFilterInput {
+ all: ReleaseFilterInput
+ any: Boolean
+ none: ReleaseFilterInput
+ some: ReleaseFilterInput
+}
+
+input ListStringOperationFilterInput {
+ all: StringOperationFilterInput
+ any: Boolean
+ none: StringOperationFilterInput
+ some: StringOperationFilterInput
+}
+
+input LongOperationFilterInput {
+ eq: Long
+ gt: Long
+ gte: Long
+ in: [Long]
+ lt: Long
+ lte: Long
+ neq: Long
+ ngt: Long
+ ngte: Long
+ nin: [Long]
+ nlt: Long
+ nlte: Long
+}
+
+input ReleaseFilterInput {
+ and: [ReleaseFilterInput!]
+ createdAt: DateTimeOperationFilterInput
+ downloadSize: LongOperationFilterInput
+ downloads: LongOperationFilterInput
+ id: UuidOperationFilterInput
+ md5Hash: StringOperationFilterInput
+ or: [ReleaseFilterInput!]
+ version: StringOperationFilterInput
+}
+
+input StringOperationFilterInput {
+ and: [StringOperationFilterInput!]
+ contains: String
+ endsWith: String
+ eq: String
+ in: [String]
+ ncontains: String
+ nendsWith: String
+ neq: String
+ nin: [String]
+ nstartsWith: String
+ or: [StringOperationFilterInput!]
+ startsWith: String
+}
+
+input UuidOperationFilterInput {
+ eq: UUID
+ gt: UUID
+ gte: UUID
+ in: [UUID]
+ lt: UUID
+ lte: UUID
+ neq: UUID
+ ngt: UUID
+ ngte: UUID
+ nin: [UUID]
+ nlt: UUID
+ nlte: UUID
+}
diff --git a/src/Artemis.sln b/src/Artemis.sln
index 2e53b5d9a..8c5b6ee51 100644
--- a/src/Artemis.sln
+++ b/src/Artemis.sln
@@ -21,6 +21,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Artemis.VisualScripting", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.WebClient.Updating", "Artemis.WebClient.Updating\Artemis.WebClient.Updating.csproj", "{7C8C6F50-0CC8-45B3-B608-A7218C005E4B}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.WebClient.Workshop", "Artemis.WebClient.Workshop\Artemis.WebClient.Workshop.csproj", "{2B982C2E-3CBC-4DAB-9167-CCCA4C78E92B}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -63,6 +65,10 @@ Global
{7C8C6F50-0CC8-45B3-B608-A7218C005E4B}.Debug|x64.Build.0 = Debug|Any CPU
{7C8C6F50-0CC8-45B3-B608-A7218C005E4B}.Release|x64.ActiveCfg = Release|Any CPU
{7C8C6F50-0CC8-45B3-B608-A7218C005E4B}.Release|x64.Build.0 = Release|Any CPU
+ {2B982C2E-3CBC-4DAB-9167-CCCA4C78E92B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {2B982C2E-3CBC-4DAB-9167-CCCA4C78E92B}.Debug|x64.Build.0 = Debug|Any CPU
+ {2B982C2E-3CBC-4DAB-9167-CCCA4C78E92B}.Release|x64.ActiveCfg = Release|Any CPU
+ {2B982C2E-3CBC-4DAB-9167-CCCA4C78E92B}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE