diff --git a/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/constructors/index.md b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/constructors/index.md new file mode 100644 index 0000000..0f7f9ab --- /dev/null +++ b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/constructors/index.md @@ -0,0 +1,19 @@ +# SimpleConsoleLogger Constructors + +**Declaring Type:** [SimpleConsoleLogger](../index.md) + +Initializes a new instance of [SimpleConsoleLogger](../index.md) + +```csharp +public SimpleConsoleLogger(SimpleConsoleLoggerOptions loggerOptions, string categoryName); +``` + +## Parameters + +`loggerOptions` [SimpleConsoleLoggerOptions](../../SimpleConsoleLoggerOptions/index.md) + +`categoryName` string + +___ + +*Documentation generated by [MdDocs](https://github.com/ap0llo/mddocs)* diff --git a/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/index.md b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/index.md new file mode 100644 index 0000000..a6cc4d4 --- /dev/null +++ b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/index.md @@ -0,0 +1,41 @@ +# SimpleConsoleLogger Class + +**Namespace:** [Grynwald.Utilities.Logging](../index.md) + +**Assembly:** Grynwald.Utilities.Logging + +A simple console logger that implements ILogger + +```csharp +[NullableContext(1)] +[Nullable(0)] +public sealed class SimpleConsoleLogger : ILogger +``` + +**Inheritance:** object → SimpleConsoleLogger + +**Attributes:** NullableContextAttribute,NullableAttribute + +**Implements:** ILogger + +## Remarks + +SimpleConsoleLogger is a implementation of ILogger that writes log messages to the console. The behavior of the logger can be customized using [SimpleConsoleLoggerOptions](../SimpleConsoleLoggerOptions/index.md). + +## Constructors + +| Name | Description | +| -------------------------------------------------------------------------------- | ------------------------------------------------- | +| [SimpleConsoleLogger(SimpleConsoleLoggerOptions, string)](constructors/index.md) | Initializes a new instance of SimpleConsoleLogger | + +## Methods + +| Name | Description | +| -------------------------------------------------------------------------------------------------------- | ------------------------------------------ | +| [BeginScope\(TState)](methods/BeginScope.md) | Begins a logical operation scope. | +| [IsEnabled(LogLevel)](methods/IsEnabled.md) | Checks if the given `logLevel` is enabled. | +| [Log\(LogLevel, EventId, TState, Exception, Func\)](methods/Log.md) | Writes a log entry. | + +___ + +*Documentation generated by [MdDocs](https://github.com/ap0llo/mddocs)* diff --git a/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/methods/BeginScope.md b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/methods/BeginScope.md new file mode 100644 index 0000000..0e76f40 --- /dev/null +++ b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/methods/BeginScope.md @@ -0,0 +1,31 @@ +# SimpleConsoleLogger.BeginScope Method + +**Declaring Type:** [SimpleConsoleLogger](../index.md) + +Begins a logical operation scope. + +```csharp +public IDisposable BeginScope(TState state); +``` + +## Type Parameters + +`TState` + +The type of the state to begin scope for. + +## Parameters + +`state` TState + +The identifier for the scope. + +## Returns + +IDisposable + +An IDisposable that ends the logical operation scope on dispose. + +___ + +*Documentation generated by [MdDocs](https://github.com/ap0llo/mddocs)* diff --git a/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/methods/IsEnabled.md b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/methods/IsEnabled.md new file mode 100644 index 0000000..657513c --- /dev/null +++ b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/methods/IsEnabled.md @@ -0,0 +1,25 @@ +# SimpleConsoleLogger.IsEnabled Method + +**Declaring Type:** [SimpleConsoleLogger](../index.md) + +Checks if the given `logLevel` is enabled. + +```csharp +public bool IsEnabled(LogLevel logLevel); +``` + +## Parameters + +`logLevel` LogLevel + +level to be checked. + +## Returns + +bool + +`true` if enabled. + +___ + +*Documentation generated by [MdDocs](https://github.com/ap0llo/mddocs)* diff --git a/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/methods/Log.md b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/methods/Log.md new file mode 100644 index 0000000..84fc141 --- /dev/null +++ b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLogger/methods/Log.md @@ -0,0 +1,41 @@ +# SimpleConsoleLogger.Log Method + +**Declaring Type:** [SimpleConsoleLogger](../index.md) + +Writes a log entry. + +```csharp +public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter); +``` + +## Type Parameters + +`TState` + +The type of the object to be written. + +## Parameters + +`logLevel` LogLevel + +Entry will be written on this level. + +`eventId` EventId + +Id of the event. + +`state` TState + +The entry to be written. Can be also an object. + +`exception` Exception + +The exception related to this entry. + +`formatter` Func\ + +Function to create a string message of the `state` and `exception`. + +___ + +*Documentation generated by [MdDocs](https://github.com/ap0llo/mddocs)* diff --git a/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/constructors/index.md b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/constructors/index.md new file mode 100644 index 0000000..1d3bf59 --- /dev/null +++ b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/constructors/index.md @@ -0,0 +1,27 @@ +# SimpleConsoleLoggerOptions Constructors + +**Declaring Type:** [SimpleConsoleLoggerOptions](../index.md) + +Initializes a new instance of [SimpleConsoleLoggerOptions](../index.md) + +```csharp +public SimpleConsoleLoggerOptions(LogLevel minimumLogLevel, bool showCategoryName, bool enabledColoredOutput); +``` + +## Parameters + +`minimumLogLevel` LogLevel + +The value to use for [MinimumLogLevel](../properties/MinimumLogLevel.md) + +`showCategoryName` bool + +The value to use for [ShowCategoryName](../properties/ShowCategoryName.md) + +`enabledColoredOutput` bool + +The value to use for [EnableColoredOutput](../properties/EnableColoredOutput.md) + +___ + +*Documentation generated by [MdDocs](https://github.com/ap0llo/mddocs)* diff --git a/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/index.md b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/index.md new file mode 100644 index 0000000..5631f93 --- /dev/null +++ b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/index.md @@ -0,0 +1,31 @@ +# SimpleConsoleLoggerOptions Class + +**Namespace:** [Grynwald.Utilities.Logging](../index.md) + +**Assembly:** Grynwald.Utilities.Logging + +Settings for [SimpleConsoleLogger](../SimpleConsoleLogger/index.md) + +```csharp +public sealed class SimpleConsoleLoggerOptions +``` + +**Inheritance:** object → SimpleConsoleLoggerOptions + +## Constructors + +| Name | Description | +| ------------------------------------------------------------------------- | -------------------------------------------------------- | +| [SimpleConsoleLoggerOptions(LogLevel, bool, bool)](constructors/index.md) | Initializes a new instance of SimpleConsoleLoggerOptions | + +## Properties + +| Name | Description | +| -------------------------------------------------------- | --------------------------------------------------------------------------- | +| [EnableColoredOutput](properties/EnableColoredOutput.md) | Gets whether console output uses colors to differentiate between log levels | +| [MinimumLogLevel](properties/MinimumLogLevel.md) | Gets the minimum log level of log messages that are written to the output | +| [ShowCategoryName](properties/ShowCategoryName.md) | Gets whether the category name of log messages is included in the output | + +___ + +*Documentation generated by [MdDocs](https://github.com/ap0llo/mddocs)* diff --git a/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/properties/EnableColoredOutput.md b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/properties/EnableColoredOutput.md new file mode 100644 index 0000000..35153f5 --- /dev/null +++ b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/properties/EnableColoredOutput.md @@ -0,0 +1,17 @@ +# SimpleConsoleLoggerOptions.EnableColoredOutput Property + +**Declaring Type:** [SimpleConsoleLoggerOptions](../index.md) + +Gets whether console output uses colors to differentiate between log levels + +```csharp +public bool EnableColoredOutput { get; } +``` + +## Property Value + +bool + +___ + +*Documentation generated by [MdDocs](https://github.com/ap0llo/mddocs)* diff --git a/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/properties/MinimumLogLevel.md b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/properties/MinimumLogLevel.md new file mode 100644 index 0000000..64caace --- /dev/null +++ b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/properties/MinimumLogLevel.md @@ -0,0 +1,17 @@ +# SimpleConsoleLoggerOptions.MinimumLogLevel Property + +**Declaring Type:** [SimpleConsoleLoggerOptions](../index.md) + +Gets the minimum log level of log messages that are written to the output + +```csharp +public LogLevel MinimumLogLevel { get; } +``` + +## Property Value + +LogLevel + +___ + +*Documentation generated by [MdDocs](https://github.com/ap0llo/mddocs)* diff --git a/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/properties/ShowCategoryName.md b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/properties/ShowCategoryName.md new file mode 100644 index 0000000..24acc8d --- /dev/null +++ b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/SimpleConsoleLoggerOptions/properties/ShowCategoryName.md @@ -0,0 +1,17 @@ +# SimpleConsoleLoggerOptions.ShowCategoryName Property + +**Declaring Type:** [SimpleConsoleLoggerOptions](../index.md) + +Gets whether the category name of log messages is included in the output + +```csharp +public bool ShowCategoryName { get; } +``` + +## Property Value + +bool + +___ + +*Documentation generated by [MdDocs](https://github.com/ap0llo/mddocs)* diff --git a/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/index.md b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/index.md new file mode 100644 index 0000000..3ab25b8 --- /dev/null +++ b/docs/api/Utilities.Logging/Grynwald/Utilities/Logging/index.md @@ -0,0 +1,14 @@ +# Grynwald.Utilities.Logging Namespace + +**Namespace:** [Grynwald.Utilities](../index.md) + +## Classes + +| Name | Description | +| ----------------------------------------------------------------- | ---------------------------------------------------------------- | +| [SimpleConsoleLogger](SimpleConsoleLogger/index.md) | A simple console logger that implements ILogger | +| [SimpleConsoleLoggerOptions](SimpleConsoleLoggerOptions/index.md) | Settings for [SimpleConsoleLogger](SimpleConsoleLogger/index.md) | + +___ + +*Documentation generated by [MdDocs](https://github.com/ap0llo/mddocs)* diff --git a/docs/api/Utilities.Logging/Grynwald/Utilities/index.md b/docs/api/Utilities.Logging/Grynwald/Utilities/index.md new file mode 100644 index 0000000..0759776 --- /dev/null +++ b/docs/api/Utilities.Logging/Grynwald/Utilities/index.md @@ -0,0 +1,11 @@ +# Grynwald.Utilities Namespace + +**Namespace:** [Grynwald](../index.md) + +## Namespaces + +- [Grynwald.Utilities.Logging](Logging/index.md) + +___ + +*Documentation generated by [MdDocs](https://github.com/ap0llo/mddocs)* diff --git a/docs/api/Utilities.Logging/Grynwald/index.md b/docs/api/Utilities.Logging/Grynwald/index.md new file mode 100644 index 0000000..6507abf --- /dev/null +++ b/docs/api/Utilities.Logging/Grynwald/index.md @@ -0,0 +1,9 @@ +# Grynwald Namespace + +## Namespaces + +- [Grynwald.Utilities](Utilities/index.md) + +___ + +*Documentation generated by [MdDocs](https://github.com/ap0llo/mddocs)* diff --git a/src/Utilities.Logging/Grynwald.Utilities.Logging.csproj b/src/Utilities.Logging/Grynwald.Utilities.Logging.csproj new file mode 100644 index 0000000..5648816 --- /dev/null +++ b/src/Utilities.Logging/Grynwald.Utilities.Logging.csproj @@ -0,0 +1,46 @@ + + + + netstandard2.0 + Enable + $(OutputPath)\$(TargetFramework)\$(AssemblyName).xml + + + + + + + + + + + + + + + + + + $(MSBuildWarningsAsMessages);IDT001 + + + + + $(MSBuildThisFileDirectory)..\..\docs\api\Utilities.Logging + true + + + + + + + + + <_Parameter1>$(MSBuildProjectName).Test + + + + diff --git a/src/Utilities.Logging/LoggerFactoryExtensions.cs b/src/Utilities.Logging/LoggerFactoryExtensions.cs new file mode 100644 index 0000000..92abf87 --- /dev/null +++ b/src/Utilities.Logging/LoggerFactoryExtensions.cs @@ -0,0 +1,28 @@ +using Microsoft.Extensions.Logging; + +namespace Grynwald.Utilities.Logging +{ + /// + /// Extension methods for to ease usage o . + /// + public static class LoggerFactoryExtensions + { + /// + /// Adds a logging provider to the logger factory + /// + public static ILoggerFactory AddSimpleConsoleLogger(this ILoggerFactory loggerFactory, SimpleConsoleLoggerConfiguration configurtation) + { + loggerFactory.AddProvider(new SimpleConsoleLoggerProvider(configurtation)); + return loggerFactory; + } + + /// + /// Adds a logging provider to the logger factory + /// + public static ILoggerFactory AddSimpleConsoleLogger(this ILoggerFactory loggerFactory) + { + loggerFactory.AddProvider(new SimpleConsoleLoggerProvider()); + return loggerFactory; + } + } +} diff --git a/src/Utilities.Logging/SimpleConsoleLogger.cs b/src/Utilities.Logging/SimpleConsoleLogger.cs new file mode 100644 index 0000000..43892d8 --- /dev/null +++ b/src/Utilities.Logging/SimpleConsoleLogger.cs @@ -0,0 +1,92 @@ +using System; +using Microsoft.Extensions.Logging; + +namespace Grynwald.Utilities.Logging +{ + /// + /// A simple console logger that implements + /// + /// + /// is a implementation of that writes log messages to the console. + /// The behavior of the logger can be customized using . + /// + public sealed class SimpleConsoleLogger : ILogger + { + private static readonly object s_ConsoleLock = new object(); + + private readonly SimpleConsoleLoggerConfiguration m_LoggerOptions; + private readonly string? m_CategoryName; + + private class LoggerScope : IDisposable + { + public void Dispose() + { } + } + + /// + /// Initializes a new instance of + /// + public SimpleConsoleLogger(SimpleConsoleLoggerConfiguration loggerOptions, string categoryName) + { + m_CategoryName = String.IsNullOrEmpty(categoryName) ? null : categoryName; + m_LoggerOptions = loggerOptions ?? throw new ArgumentNullException(nameof(loggerOptions)); + } + + /// + public IDisposable BeginScope(TState state) => new LoggerScope(); + + /// + public bool IsEnabled(LogLevel logLevel) => logLevel >= m_LoggerOptions.MinimumLogLevel; + + /// + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + if (!IsEnabled(logLevel)) + return; + + var color = GetConsoleColor(logLevel); + + var message = (!m_LoggerOptions.ShowCategoryName || m_CategoryName == null) + ? $"{logLevel.ToString().ToUpper()} - {formatter(state, exception)}" + : $"{logLevel.ToString().ToUpper()} - {m_CategoryName} - {formatter(state, exception)}"; + + lock (s_ConsoleLock) + { + if (color.HasValue) + { + var previousColor = Console.ForegroundColor; + Console.ForegroundColor = color.Value; + Console.WriteLine(message); + Console.ForegroundColor = previousColor; + } + else + { + Console.WriteLine(message); + } + } + } + + + private ConsoleColor? GetConsoleColor(LogLevel logLevel) + { + if (!m_LoggerOptions.EnableColoredOutput) + return null; + + switch (logLevel) + { + case LogLevel.Information: + return ConsoleColor.White; + + case LogLevel.Warning: + return ConsoleColor.Yellow; + + case LogLevel.Error: + case LogLevel.Critical: + return ConsoleColor.Red; + + default: + return null; + } + } + } +} diff --git a/src/Utilities.Logging/SimpleConsoleLoggerConfiguration.cs b/src/Utilities.Logging/SimpleConsoleLoggerConfiguration.cs new file mode 100644 index 0000000..cf539ca --- /dev/null +++ b/src/Utilities.Logging/SimpleConsoleLoggerConfiguration.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.Logging; + +namespace Grynwald.Utilities.Logging +{ + /// + /// Settings for + /// + public sealed class SimpleConsoleLoggerConfiguration + { + /// + /// Gets the default logger settings + /// + public static readonly SimpleConsoleLoggerConfiguration Default = new SimpleConsoleLoggerConfiguration(LogLevel.Information, true, true); + + /// + /// Gets the minimum log level of log messages that are written to the output + /// + public LogLevel MinimumLogLevel { get; } + + /// + /// Gets whether the category name of log messages is included in the output + /// + public bool ShowCategoryName { get; } + + /// + /// Gets whether console output uses colors to differentiate between log levels + /// + public bool EnableColoredOutput { get; } + + + /// + /// Initializes a new instance of + /// + /// The value to use for + /// The value to use for + /// The value to use for + public SimpleConsoleLoggerConfiguration(LogLevel minimumLogLevel, bool showCategoryName, bool enabledColoredOutput) + { + MinimumLogLevel = minimumLogLevel; + ShowCategoryName = showCategoryName; + EnableColoredOutput = enabledColoredOutput; + } + } +} diff --git a/src/Utilities.Logging/SimpleConsoleLoggerProvider.cs b/src/Utilities.Logging/SimpleConsoleLoggerProvider.cs new file mode 100644 index 0000000..725fe25 --- /dev/null +++ b/src/Utilities.Logging/SimpleConsoleLoggerProvider.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; + +namespace Grynwald.Utilities.Logging +{ + internal sealed class SimpleConsoleLoggerProvider : ILoggerProvider + { + private static readonly object s_Lock = new object(); + private readonly IDictionary m_Loggers = new Dictionary(); + private readonly SimpleConsoleLoggerConfiguration m_LoggerOptions; + + public SimpleConsoleLoggerProvider() : this(SimpleConsoleLoggerConfiguration.Default) + { } + + public SimpleConsoleLoggerProvider(SimpleConsoleLoggerConfiguration loggerOptions) + { + m_LoggerOptions = loggerOptions ?? throw new ArgumentNullException(nameof(loggerOptions)); + } + + + public ILogger CreateLogger(string categoryName) + { + lock (s_Lock) + { + if (m_Loggers.TryGetValue(categoryName, out var logger)) + { + return logger; + } + else + { + logger = new SimpleConsoleLogger(m_LoggerOptions, categoryName); + m_Loggers.Add(categoryName, logger); + return logger; + } + } + } + + public void Dispose() + { + lock (s_Lock) + { + m_Loggers.Clear(); + } + } + } +} diff --git a/src/Utilities.sln b/src/Utilities.sln index dd59194..b9d9b5f 100644 --- a/src/Utilities.sln +++ b/src/Utilities.sln @@ -22,6 +22,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Grynwald.Utilities.Configur EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Grynwald.Utilities", "Grynwald.Utilities", "{E7229523-011C-4AC8-9384-DF54226FFC6A}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grynwald.Utilities.Logging", "Utilities.Logging\Grynwald.Utilities.Logging.csproj", "{7E3EC71C-12F8-4923-9CDA-350F34A09ED3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Grynwald.Utilities.Logging", "Grynwald.Utilities.Logging", "{EA7538A0-CFE5-4F1D-9988-0C02E72CE503}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -92,6 +96,18 @@ Global {8F170DDF-4DF0-4915-A636-BF397E9E35EB}.Release|x64.Build.0 = Release|Any CPU {8F170DDF-4DF0-4915-A636-BF397E9E35EB}.Release|x86.ActiveCfg = Release|Any CPU {8F170DDF-4DF0-4915-A636-BF397E9E35EB}.Release|x86.Build.0 = Release|Any CPU + {7E3EC71C-12F8-4923-9CDA-350F34A09ED3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7E3EC71C-12F8-4923-9CDA-350F34A09ED3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7E3EC71C-12F8-4923-9CDA-350F34A09ED3}.Debug|x64.ActiveCfg = Debug|Any CPU + {7E3EC71C-12F8-4923-9CDA-350F34A09ED3}.Debug|x64.Build.0 = Debug|Any CPU + {7E3EC71C-12F8-4923-9CDA-350F34A09ED3}.Debug|x86.ActiveCfg = Debug|Any CPU + {7E3EC71C-12F8-4923-9CDA-350F34A09ED3}.Debug|x86.Build.0 = Debug|Any CPU + {7E3EC71C-12F8-4923-9CDA-350F34A09ED3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7E3EC71C-12F8-4923-9CDA-350F34A09ED3}.Release|Any CPU.Build.0 = Release|Any CPU + {7E3EC71C-12F8-4923-9CDA-350F34A09ED3}.Release|x64.ActiveCfg = Release|Any CPU + {7E3EC71C-12F8-4923-9CDA-350F34A09ED3}.Release|x64.Build.0 = Release|Any CPU + {7E3EC71C-12F8-4923-9CDA-350F34A09ED3}.Release|x86.ActiveCfg = Release|Any CPU + {7E3EC71C-12F8-4923-9CDA-350F34A09ED3}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -102,6 +118,7 @@ Global {A2E64D65-8B8E-4824-BFB9-779FF6269E83} = {E7229523-011C-4AC8-9384-DF54226FFC6A} {FA9AF47C-176B-48A9-BFAE-212D84E589AC} = {D50D3DC4-5827-44BA-8816-95B678072131} {8F170DDF-4DF0-4915-A636-BF397E9E35EB} = {D50D3DC4-5827-44BA-8816-95B678072131} + {7E3EC71C-12F8-4923-9CDA-350F34A09ED3} = {EA7538A0-CFE5-4F1D-9988-0C02E72CE503} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AEDB45B9-3EC6-4245-9DBA-4321594B64A0}