diff --git a/MN.L10n.Analyzer/MN.L10n.Analyzer.Test/MN.L10n.Analyzer.Test.csproj b/MN.L10n.Analyzer/MN.L10n.Analyzer.Test/MN.L10n.Analyzer.Test.csproj
index 78ee7ec..2293206 100644
--- a/MN.L10n.Analyzer/MN.L10n.Analyzer.Test/MN.L10n.Analyzer.Test.csproj
+++ b/MN.L10n.Analyzer/MN.L10n.Analyzer.Test/MN.L10n.Analyzer.Test.csproj
@@ -11,7 +11,7 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/MN.L10n.Analyzer/MN.L10n.Analyzer.Test/MNL10nAnalyzerUnitTests.cs b/MN.L10n.Analyzer/MN.L10n.Analyzer.Test/MNL10nAnalyzerUnitTests.cs
index 566f51b..a65a99e 100644
--- a/MN.L10n.Analyzer/MN.L10n.Analyzer.Test/MNL10nAnalyzerUnitTests.cs
+++ b/MN.L10n.Analyzer/MN.L10n.Analyzer.Test/MNL10nAnalyzerUnitTests.cs
@@ -416,6 +416,32 @@ public void Main() {
VerifyCSharpDiagnostic(test, expectations.ToArray());
}
+ [Fact]
+ public void Test_MN0009_MissingKeywordsWhenArgumentIsNull()
+ {
+ var test = @"
+ namespace ConsoleApplication1
+ {
+ class TypeName
+ {
+ public void Main() {
+ _s(""Testing $someParameter$"", null);
+ }
+ }
+ }";
+
+ VerifyCSharpDiagnostic(test, new DiagnosticResult
+ {
+ Id = "MN0009",
+ Message = "L10n is missing '$someParameter$' in the object for keywords",
+ Severity = DiagnosticSeverity.Error,
+ Locations =
+ [
+ new DiagnosticResultLocation("Test0.cs", 7, 6)
+ ]
+ });
+ }
+
protected override CodeFixProvider GetCSharpCodeFixProvider()
{
return new MNL10nCodeFixProvider();
diff --git a/MN.L10n.Analyzer/MN.L10n.Analyzer.Vsix/MN.L10n.Analyzer.Vsix.csproj b/MN.L10n.Analyzer/MN.L10n.Analyzer.Vsix/MN.L10n.Analyzer.Vsix.csproj
deleted file mode 100644
index e1cbacc..0000000
--- a/MN.L10n.Analyzer/MN.L10n.Analyzer.Vsix/MN.L10n.Analyzer.Vsix.csproj
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-
-
- 15.0
- $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
-
- 14.0
-
-
-
-
-
- Debug
- AnyCPU
- AnyCPU
- 2.0
- {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- {0FBE481E-769A-4818-896E-3CD4580CA7A2}
- Library
- Properties
- MN.L10n.Analyzer.Vsix
- MN.L10n.Analyzer
- v4.7.2
- false
- false
- false
- false
- false
- false
- Roslyn
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
- Program
- $(DevEnvDir)devenv.exe
- /rootsuffix Roslyn
-
-
-
- .editorconfig
-
-
- Designer
-
-
-
-
- {C47AC9D6-C6AF-45A6-9596-3A63B48EEA9C}
- MN.L10n.Analyzer
-
-
-
-
-
\ No newline at end of file
diff --git a/MN.L10n.Analyzer/MN.L10n.Analyzer.Vsix/source.extension.vsixmanifest b/MN.L10n.Analyzer/MN.L10n.Analyzer.Vsix/source.extension.vsixmanifest
deleted file mode 100644
index ef7e42f..0000000
--- a/MN.L10n.Analyzer/MN.L10n.Analyzer.Vsix/source.extension.vsixmanifest
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
- MN.L10n.Analyzer
- This is a sample diagnostic extension for the .NET Compiler Platform ("Roslyn").
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/MN.L10n.Analyzer/MN.L10n.Analyzer/AnalyzerReleases.Shipped.md b/MN.L10n.Analyzer/MN.L10n.Analyzer/AnalyzerReleases.Shipped.md
index ff90a90..a84311f 100644
--- a/MN.L10n.Analyzer/MN.L10n.Analyzer/AnalyzerReleases.Shipped.md
+++ b/MN.L10n.Analyzer/MN.L10n.Analyzer/AnalyzerReleases.Shipped.md
@@ -7,7 +7,6 @@
Rule ID | Category | Severity | Notes
--------|----------|----------|-------
-MN0001 | L10n | Error | MNL10nAnalyzer
MN0002 | L10n | Error | MNL10nAnalyzer
MN0003 | L10n | Error | MNL10nAnalyzer
MN0004 | L10n | Error | MNL10nAnalyzer
diff --git a/MN.L10n.Analyzer/MN.L10n.Analyzer/MN.L10n.Analyzer.csproj b/MN.L10n.Analyzer/MN.L10n.Analyzer/MN.L10n.Analyzer.csproj
index 6ae1812..9aa6eaa 100644
--- a/MN.L10n.Analyzer/MN.L10n.Analyzer/MN.L10n.Analyzer.csproj
+++ b/MN.L10n.Analyzer/MN.L10n.Analyzer/MN.L10n.Analyzer.csproj
@@ -2,10 +2,13 @@
netstandard2.0
- false
True
true
true
+ enable
+ latest
+ true
+ false
@@ -21,17 +24,15 @@
MN.L10n.Analyzer, analyzers
true
- 4.0.2
+ 5.0.0
MultiNet Interactive AB
-
-
- x64
-
-
-
-
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
@@ -39,14 +40,13 @@
-
-
-
-
-
-
+
+
+
+
+
diff --git a/MN.L10n.Analyzer/MN.L10n.Analyzer/MNL10nAnalyzer.cs b/MN.L10n.Analyzer/MN.L10n.Analyzer/MNL10nAnalyzer.cs
index 01e60d7..46f7b9d 100644
--- a/MN.L10n.Analyzer/MN.L10n.Analyzer/MNL10nAnalyzer.cs
+++ b/MN.L10n.Analyzer/MN.L10n.Analyzer/MNL10nAnalyzer.cs
@@ -2,143 +2,139 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
-using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text.RegularExpressions;
-namespace MN.L10n.Analyzer
+namespace MN.L10n.Analyzer;
+
+[DiagnosticAnalyzer(LanguageNames.CSharp)]
+public class MNL10nAnalyzer : DiagnosticAnalyzer
{
- [DiagnosticAnalyzer(LanguageNames.CSharp)]
- public class MNL10nAnalyzer : DiagnosticAnalyzer
+ public static readonly DiagnosticDescriptor MemberAccessorRule = new DiagnosticDescriptor("MN0002", "Input is not a known string", "L10n can only evaluate string literals when finding used phrases. If the phrase is known you can ignore this, but you should only use L10n with known strings when possible.", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
+ public static readonly DiagnosticDescriptor NoWhitespaceAtStartOrEndRule = new DiagnosticDescriptor("MN0003", "String starts/ends with whitespace", "The string cannot start or end with whitespaces", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
+ public static readonly DiagnosticDescriptor NoEmptyStringsEndRule = new DiagnosticDescriptor("MN0004", "Input is an empty string", "The string cannot start or end with whitespace", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
+ public static readonly DiagnosticDescriptor NoStringInterpolationRule = new DiagnosticDescriptor("MN0005", "Interpolated string used", "L10n can only evaluate string literals when finding used phrases. Never use string interpolation with L10n. It is not supported yet.", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
+ public static readonly DiagnosticDescriptor NoStringConcatRule = new DiagnosticDescriptor("MN0006", "String concatenation used", "L10n can only evaluate a single string literal when finding used phrases. Never use string concatenation with L10n. It is not supported yet.", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
+ public static readonly DiagnosticDescriptor ArgumentsNotAnClassOrNullRule = new DiagnosticDescriptor("MN0007", "Invalid type for keywords", "L10n requires a class or anonymous type (or explicitly null) for keywords", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
+ public static readonly DiagnosticDescriptor MissingKeywordReplacementObjectRule = new DiagnosticDescriptor("MN0008", "Missing object for keyword replacement", "L10n requires a class or anonymous type (or explicitly null) for keywords", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
+ public static readonly DiagnosticDescriptor MissingKeywordsInReplacementObjectRule = new DiagnosticDescriptor("MN0009", "Missing property for keyword replacement", "L10n is missing '{0}' in the object for keywords", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
+
+ public override ImmutableArray SupportedDiagnostics
{
- public static readonly DiagnosticDescriptor NoParamRule = new DiagnosticDescriptor("MN0001", "Missing arguments", "Need to send variables to '{0}'", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
- public static readonly DiagnosticDescriptor MemberAccessorRule = new DiagnosticDescriptor("MN0002", "Input is not a known string", "L10n can only evaluate string literals when finding used phrases. If the phrase is known you can ignore this, but you should only use L10n with known strings when possible.", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
- public static readonly DiagnosticDescriptor NoWhitespaceAtStartOrEndRule = new DiagnosticDescriptor("MN0003", "String starts/ends with whitespace", "The string cannot start or end with whitespaces", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
- public static readonly DiagnosticDescriptor NoEmptyStringsEndRule = new DiagnosticDescriptor("MN0004", "Input is an empty string", "The string cannot start or end with whitespace", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
- public static readonly DiagnosticDescriptor NoStringInterpolationRule = new DiagnosticDescriptor("MN0005", "Interpolated string used", "L10n can only evaluate string literals when finding used phrases. Never use string interpolation with L10n. It is not supported yet.", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
- public static readonly DiagnosticDescriptor NoStringConcatRule = new DiagnosticDescriptor("MN0006", "String concatenation used", "L10n can only evaluate a single string literal when finding used phrases. Never use string concatenation with L10n. It is not supported yet.", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
- public static readonly DiagnosticDescriptor ArgumentsNotAnClassOrNullRule = new DiagnosticDescriptor("MN0007", "Invalid type for keywords", "L10n requires a class or anonymous type (or explicitly null) for keywords", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
- public static readonly DiagnosticDescriptor MissingKeywordReplacementObjectRule = new DiagnosticDescriptor("MN0008", "Missing object for keyword replacement", "L10n requires a class or anonymous type (or explicitly null) for keywords", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
- public static readonly DiagnosticDescriptor MissingKeywordsInReplacementObjectRule = new DiagnosticDescriptor("MN0009", "Missing property for keyword replacement", "L10n is missing '{0}' in the object for keywords", "L10n", DiagnosticSeverity.Error, isEnabledByDefault: true);
-
- public override ImmutableArray SupportedDiagnostics
+ get
{
- get
- {
- return ImmutableArray.Create(
- NoParamRule,
- MemberAccessorRule,
- NoWhitespaceAtStartOrEndRule,
- NoEmptyStringsEndRule,
- NoStringInterpolationRule,
- NoStringConcatRule,
- ArgumentsNotAnClassOrNullRule,
- MissingKeywordReplacementObjectRule,
- MissingKeywordsInReplacementObjectRule
- );
- }
+ return ImmutableArray.Create(
+ MemberAccessorRule,
+ NoWhitespaceAtStartOrEndRule,
+ NoEmptyStringsEndRule,
+ NoStringInterpolationRule,
+ NoStringConcatRule,
+ ArgumentsNotAnClassOrNullRule,
+ MissingKeywordReplacementObjectRule,
+ MissingKeywordsInReplacementObjectRule
+ );
}
+ }
- public override void Initialize(AnalysisContext context)
- {
- context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
- context.EnableConcurrentExecution();
- context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.InvocationExpression);
- }
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+ context.EnableConcurrentExecution();
+ context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.InvocationExpression);
+ }
- private static readonly string[] validIdentifiers = new[]
- {
- "_s", "_m",
- "L10n._s", "L10n._m",
- };
+ private static readonly string[] validIdentifiers = new[]
+ {
+ "_s", "_m",
+ "L10n._s", "L10n._m",
+ };
- static Regex r = new Regex(@"(\$(?:[a-zA-Z0-9_]+?)\$)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ static Regex r = new Regex(@"(\$(?:[a-zA-Z0-9_]+?)\$)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
- public static HashSet L10nParameters(string input) => new HashSet(r.Matches(input).Cast().Select(m => m.Groups[1].Value));
+ public static HashSet L10nParameters(string input) => new HashSet(r.Matches(input).Cast().Select(m => m.Groups[1].Value));
- private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext obj)
- {
- if (!(obj.Node is InvocationExpressionSyntax ies)) return;
+ private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext obj)
+ {
+ if (!(obj.Node is InvocationExpressionSyntax ies)) return;
- var identifier = (ies.Expression as IdentifierNameSyntax)?.Identifier.Text
- ?? (ies.Expression as MemberAccessExpressionSyntax)?.ToString();
+ var identifier = (ies.Expression as IdentifierNameSyntax)?.Identifier.Text
+ ?? (ies.Expression as MemberAccessExpressionSyntax)?.ToString();
- if (!validIdentifiers.Contains(identifier)) return;
+ if (!validIdentifiers.Contains(identifier)) return;
- HashSet l10nParameters = null;
+ HashSet? l10nParameters = null;
- var arguments = ies.ArgumentList.Arguments;
- if (arguments.Count == 0)
- obj.ReportDiagnostic(Diagnostic.Create(NoParamRule, obj.Node.GetLocation()));
- else
+ var arguments = ies.ArgumentList.Arguments;
+ if (arguments.Count > 0)
+ {
+ var supposedString = arguments.First();
+ switch (supposedString.Expression)
{
- var supposedString = arguments.First();
- switch (supposedString.Expression)
- {
- case BinaryExpressionSyntax binaryExpression:
- obj.ReportDiagnostic(Diagnostic.Create(NoStringConcatRule, obj.Node.GetLocation()));
- break;
- case MemberAccessExpressionSyntax memberAccess:
- case InvocationExpressionSyntax invocationExpression:
- obj.ReportDiagnostic(Diagnostic.Create(MemberAccessorRule, obj.Node.GetLocation()));
- break;
- case InterpolatedStringExpressionSyntax interpolatedString:
- obj.ReportDiagnostic(Diagnostic.Create(NoStringInterpolationRule, obj.Node.GetLocation()));
- break;
- case LiteralExpressionSyntax literalExpression:
- var text = literalExpression.Token.ValueText;
- if (string.IsNullOrWhiteSpace(text))
+ case BinaryExpressionSyntax binaryExpression:
+ obj.ReportDiagnostic(Diagnostic.Create(NoStringConcatRule, obj.Node.GetLocation()));
+ break;
+ case MemberAccessExpressionSyntax memberAccess:
+ case InvocationExpressionSyntax invocationExpression:
+ obj.ReportDiagnostic(Diagnostic.Create(MemberAccessorRule, obj.Node.GetLocation()));
+ break;
+ case InterpolatedStringExpressionSyntax interpolatedString:
+ obj.ReportDiagnostic(Diagnostic.Create(NoStringInterpolationRule, obj.Node.GetLocation()));
+ break;
+ case LiteralExpressionSyntax literalExpression:
+ var text = literalExpression.Token.ValueText;
+ if (string.IsNullOrWhiteSpace(text))
+ {
+ obj.ReportDiagnostic(Diagnostic.Create(NoEmptyStringsEndRule, obj.Node.GetLocation()));
+ }
+ else
+ {
+ if (char.IsWhiteSpace(text.First()) || char.IsWhiteSpace(text.Last()))
{
- obj.ReportDiagnostic(Diagnostic.Create(NoEmptyStringsEndRule, obj.Node.GetLocation()));
+ obj.ReportDiagnostic(Diagnostic.Create(NoWhitespaceAtStartOrEndRule, obj.Node.GetLocation()));
}
- else
+ }
+
+ if (text.Contains("$"))
+ {
+ l10nParameters = L10nParameters(text);
+
+ if (arguments.Count == 1)
{
- if (char.IsWhiteSpace(text.First()) || char.IsWhiteSpace(text.Last()))
- {
- obj.ReportDiagnostic(Diagnostic.Create(NoWhitespaceAtStartOrEndRule, obj.Node.GetLocation()));
- }
+ obj.ReportDiagnostic(Diagnostic.Create(MissingKeywordReplacementObjectRule, obj.Node.GetLocation()));
}
+ }
- if (text.Contains("$"))
- {
- l10nParameters = L10nParameters(text);
+ break;
+ }
- if (arguments.Count == 1)
- {
- obj.ReportDiagnostic(Diagnostic.Create(MissingKeywordReplacementObjectRule, obj.Node.GetLocation()));
- }
- }
+ if (arguments.Count > 1)
+ {
+ var supposedArgument = arguments[1];
- break;
+ if (!(supposedArgument.Expression is ObjectCreationExpressionSyntax || supposedArgument.Expression is AnonymousObjectCreationExpressionSyntax || supposedArgument.Expression.RawKind == (int)SyntaxKind.NullLiteralExpression))
+ {
+ obj.ReportDiagnostic(Diagnostic.Create(ArgumentsNotAnClassOrNullRule, obj.Node.GetLocation()));
}
-
- if (arguments.Count > 1)
+ else
{
- var supposedArgument = arguments[1];
-
- if (!(supposedArgument.Expression is ObjectCreationExpressionSyntax || supposedArgument.Expression is AnonymousObjectCreationExpressionSyntax || supposedArgument.Expression.RawKind == (int)SyntaxKind.NullLiteralExpression))
+ if (l10nParameters == null || l10nParameters.Count == 0)
{
- obj.ReportDiagnostic(Diagnostic.Create(ArgumentsNotAnClassOrNullRule, obj.Node.GetLocation()));
+ return;
}
- else
- {
- if (l10nParameters == null || l10nParameters.Count == 0)
- {
- return;
- }
- var argumentAsObject = obj.SemanticModel.GetSymbolInfo(supposedArgument.Expression).Symbol;
+ var argumentAsObject = obj.SemanticModel.GetSymbolInfo(supposedArgument.Expression).Symbol;
- var missingParameters = l10nParameters.Except(argumentAsObject.ContainingType.MemberNames.Select(p => $"${p}$"));
+ var missingParameters = argumentAsObject == null ? l10nParameters.ToArray() :
+ l10nParameters.Except(argumentAsObject.ContainingType.MemberNames.Select(p => $"${p}$"))
+ .ToArray();
- if (missingParameters.Any())
+ if (missingParameters.Any())
+ {
+ foreach (var p in missingParameters)
{
- foreach (var p in missingParameters)
- {
- obj.ReportDiagnostic(Diagnostic.Create(MissingKeywordsInReplacementObjectRule, obj.Node.GetLocation(), p));
- }
+ obj.ReportDiagnostic(Diagnostic.Create(MissingKeywordsInReplacementObjectRule, obj.Node.GetLocation(), p));
}
}
}
diff --git a/MN.L10n.Analyzer/MN.L10n.Analyzer/MNL10nCodeFixProvider.cs b/MN.L10n.Analyzer/MN.L10n.Analyzer/MNL10nCodeFixProvider.cs
index 45eb5fa..ebb0c28 100644
--- a/MN.L10n.Analyzer/MN.L10n.Analyzer/MNL10nCodeFixProvider.cs
+++ b/MN.L10n.Analyzer/MN.L10n.Analyzer/MNL10nCodeFixProvider.cs
@@ -14,7 +14,6 @@ public class MNL10nCodeFixProvider : CodeFixProvider
public sealed override ImmutableArray FixableDiagnosticIds {
get {
return ImmutableArray.Create(
- MNL10nAnalyzer.NoParamRule.Id,
MNL10nAnalyzer.MemberAccessorRule.Id,
MNL10nAnalyzer.NoEmptyStringsEndRule.Id,
MNL10nAnalyzer.NoWhitespaceAtStartOrEndRule.Id,
diff --git a/MN.L10n.sln b/MN.L10n.sln
index 34789cb..08f6f07 100644
--- a/MN.L10n.sln
+++ b/MN.L10n.sln
@@ -33,8 +33,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MN.L10n.Analyzer", "MN.L10n
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MN.L10n.Analyzer.Test", "MN.L10n.Analyzer\MN.L10n.Analyzer.Test\MN.L10n.Analyzer.Test.csproj", "{45A4B5FB-A04C-40E0-BA01-250E2E6C308B}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MN.L10n.Analyzer.Vsix", "MN.L10n.Analyzer\MN.L10n.Analyzer.Vsix\MN.L10n.Analyzer.Vsix.csproj", "{0FBE481E-769A-4818-896E-3CD4580CA7A2}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MN.L10n.SystemWeb", "MN.L10n.SystemWeb\MN.L10n.SystemWeb.csproj", "{8096E105-0A0B-446F-89DE-599312C7E25E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MN.L10n.Tests", "MN.L10n.Tests\MN.L10n.Tests.csproj", "{80D8F7EE-7A63-41DB-9FD4-D0D4D1D69F21}"
@@ -85,10 +83,6 @@ Global
{45A4B5FB-A04C-40E0-BA01-250E2E6C308B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45A4B5FB-A04C-40E0-BA01-250E2E6C308B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{45A4B5FB-A04C-40E0-BA01-250E2E6C308B}.Release|Any CPU.Build.0 = Release|Any CPU
- {0FBE481E-769A-4818-896E-3CD4580CA7A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0FBE481E-769A-4818-896E-3CD4580CA7A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0FBE481E-769A-4818-896E-3CD4580CA7A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0FBE481E-769A-4818-896E-3CD4580CA7A2}.Release|Any CPU.Build.0 = Release|Any CPU
{8096E105-0A0B-446F-89DE-599312C7E25E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8096E105-0A0B-446F-89DE-599312C7E25E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8096E105-0A0B-446F-89DE-599312C7E25E}.Release|Any CPU.ActiveCfg = Release|Any CPU