diff --git a/docs/release-notes.md b/docs/release-notes.md
index abe07dd9..48a47af6 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -17,6 +17,7 @@
* For SMAPI developers:
* When deploying web services to a single-instance app, the MongoDB server can now be replaced with in-memory storage.
+ * Merged the separate legacy redirects app on AWS into the main app on Azure.
## 3.5
Released 27 April 2020 for Stardew Valley 1.4.1 or later.
diff --git a/src/SMAPI.Web.LegacyRedirects/Controllers/ModsApiController.cs b/src/SMAPI.Web.LegacyRedirects/Controllers/ModsApiController.cs
deleted file mode 100644
index 44ed0b6b..00000000
--- a/src/SMAPI.Web.LegacyRedirects/Controllers/ModsApiController.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Mvc;
-using Pathoschild.Http.Client;
-using StardewModdingAPI.Toolkit.Framework.Clients.WebApi;
-
-namespace SMAPI.Web.LegacyRedirects.Controllers
-{
- /// Provides an API to perform mod update checks.
- [ApiController]
- [Produces("application/json")]
- [Route("api/v{version}/mods")]
- public class ModsApiController : Controller
- {
- /*********
- ** Public methods
- *********/
- /// Fetch version metadata for the given mods.
- /// The mod search criteria.
- [HttpPost]
- public async Task> PostAsync([FromBody] ModSearchModel model)
- {
- using IClient client = new FluentClient("https://smapi.io/api");
-
- Startup.ConfigureJsonNet(client.Formatters.JsonFormatter.SerializerSettings);
-
- return await client
- .PostAsync(this.Request.Path)
- .WithBody(model)
- .AsArray();
- }
- }
-}
diff --git a/src/SMAPI.Web.LegacyRedirects/Framework/LambdaRewriteRule.cs b/src/SMAPI.Web.LegacyRedirects/Framework/LambdaRewriteRule.cs
deleted file mode 100644
index e5138e5c..00000000
--- a/src/SMAPI.Web.LegacyRedirects/Framework/LambdaRewriteRule.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Rewrite;
-
-namespace SMAPI.Web.LegacyRedirects.Framework
-{
- /// Rewrite requests to prepend the subdomain portion (if any) to the path.
- /// Derived from .
- internal class LambdaRewriteRule : IRule
- {
- /*********
- ** Accessors
- *********/
- /// Rewrite an HTTP request if needed.
- private readonly Action Rewrite;
-
-
- /*********
- ** Public methods
- *********/
- /// Construct an instance.
- /// Rewrite an HTTP request if needed.
- public LambdaRewriteRule(Action rewrite)
- {
- this.Rewrite = rewrite ?? throw new ArgumentNullException(nameof(rewrite));
- }
-
- /// Applies the rule. Implementations of ApplyRule should set the value for (defaults to RuleResult.ContinueRules).
- /// The rewrite context.
- public void ApplyRule(RewriteContext context)
- {
- HttpRequest request = context.HttpContext.Request;
- HttpResponse response = context.HttpContext.Response;
- this.Rewrite(context, request, response);
- }
- }
-}
diff --git a/src/SMAPI.Web.LegacyRedirects/Program.cs b/src/SMAPI.Web.LegacyRedirects/Program.cs
deleted file mode 100644
index 6adee877..00000000
--- a/src/SMAPI.Web.LegacyRedirects/Program.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.Hosting;
-
-namespace SMAPI.Web.LegacyRedirects
-{
- /// The main app entry point.
- public class Program
- {
- /*********
- ** Public methods
- *********/
- /// The main app entry point.
- /// The command-line arguments.
- public static void Main(string[] args)
- {
- Host
- .CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(builder => builder.UseStartup())
- .Build()
- .Run();
- }
- }
-}
diff --git a/src/SMAPI.Web.LegacyRedirects/Properties/launchSettings.json b/src/SMAPI.Web.LegacyRedirects/Properties/launchSettings.json
deleted file mode 100644
index e9a1b210..00000000
--- a/src/SMAPI.Web.LegacyRedirects/Properties/launchSettings.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:52756",
- "sslPort": 0
- }
- },
- "$schema": "http://json.schemastore.org/launchsettings.json",
- "profiles": {
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "SMAPI.Web.LegacyRedirects": {
- "commandName": "Project",
- "launchBrowser": true,
- "launchUrl": "/",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- },
- "applicationUrl": "https://localhost:5001;http://localhost:5000"
- }
- }
-}
\ No newline at end of file
diff --git a/src/SMAPI.Web.LegacyRedirects/SMAPI.Web.LegacyRedirects.csproj b/src/SMAPI.Web.LegacyRedirects/SMAPI.Web.LegacyRedirects.csproj
deleted file mode 100644
index 15ca7272..00000000
--- a/src/SMAPI.Web.LegacyRedirects/SMAPI.Web.LegacyRedirects.csproj
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
- netcoreapp3.0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/SMAPI.Web/Framework/RedirectRules/RedirectHostsToUrlsRule.cs b/src/SMAPI.Web/Framework/RedirectRules/RedirectHostsToUrlsRule.cs
new file mode 100644
index 00000000..d75ee791
--- /dev/null
+++ b/src/SMAPI.Web/Framework/RedirectRules/RedirectHostsToUrlsRule.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Net;
+using Microsoft.AspNetCore.Rewrite;
+
+namespace StardewModdingAPI.Web.Framework.RedirectRules
+{
+ /// Redirect hostnames to a URL if they match a condition.
+ internal class RedirectHostsToUrlsRule : RedirectMatchRule
+ {
+ /*********
+ ** Fields
+ *********/
+ /// Maps a lowercase hostname to the resulting redirect URL.
+ private readonly Func Map;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// Construct an instance.
+ /// The status code to use for redirects.
+ /// Hostnames mapped to the resulting redirect URL.
+ public RedirectHostsToUrlsRule(HttpStatusCode statusCode, Func map)
+ {
+ this.StatusCode = statusCode;
+ this.Map = map ?? throw new ArgumentNullException(nameof(map));
+ }
+
+
+ /*********
+ ** Private methods
+ *********/
+ /// Get the new redirect URL.
+ /// The rewrite context.
+ /// Returns the redirect URL, or null if the redirect doesn't apply.
+ protected override string GetNewUrl(RewriteContext context)
+ {
+ // get requested host
+ string host = context.HttpContext.Request.Host.Host;
+ if (host == null)
+ return null;
+
+ // get new host
+ host = this.Map(host);
+ if (host == null)
+ return null;
+
+ // rewrite URL
+ UriBuilder uri = this.GetUrl(context.HttpContext.Request);
+ uri.Host = host;
+ return uri.ToString();
+ }
+ }
+}
diff --git a/src/SMAPI.Web/Framework/RedirectRules/RedirectMatchRule.cs b/src/SMAPI.Web/Framework/RedirectRules/RedirectMatchRule.cs
new file mode 100644
index 00000000..6e81c4ca
--- /dev/null
+++ b/src/SMAPI.Web/Framework/RedirectRules/RedirectMatchRule.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Net;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Rewrite;
+
+namespace StardewModdingAPI.Web.Framework.RedirectRules
+{
+ /// Redirect matching requests to a URL.
+ internal abstract class RedirectMatchRule : IRule
+ {
+ /*********
+ ** Fields
+ *********/
+ /// The status code to use for redirects.
+ protected HttpStatusCode StatusCode { get; set; } = HttpStatusCode.Redirect;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// Applies the rule. Implementations of ApplyRule should set the value for (defaults to RuleResult.ContinueRules).
+ /// The rewrite context.
+ public void ApplyRule(RewriteContext context)
+ {
+ string newUrl = this.GetNewUrl(context);
+ if (newUrl == null)
+ return;
+
+ HttpResponse response = context.HttpContext.Response;
+ response.StatusCode = (int)HttpStatusCode.Redirect;
+ response.Headers["Location"] = newUrl;
+ context.Result = RuleResult.EndResponse;
+ }
+
+
+ /*********
+ ** Protected methods
+ *********/
+ /// Get the new redirect URL.
+ /// The rewrite context.
+ /// Returns the redirect URL, or null if the redirect doesn't apply.
+ protected abstract string GetNewUrl(RewriteContext context);
+
+ /// Get the full request URL.
+ /// The request.
+ protected UriBuilder GetUrl(HttpRequest request)
+ {
+ return new UriBuilder
+ {
+ Scheme = request.Scheme,
+ Host = request.Host.Host,
+ Port = request.Host.Port ?? -1,
+ Path = request.PathBase + request.Path,
+ Query = request.QueryString.Value
+ };
+ }
+ }
+}
diff --git a/src/SMAPI.Web/Framework/RedirectRules/RedirectPathsToUrlsRule.cs b/src/SMAPI.Web/Framework/RedirectRules/RedirectPathsToUrlsRule.cs
new file mode 100644
index 00000000..16397c1e
--- /dev/null
+++ b/src/SMAPI.Web/Framework/RedirectRules/RedirectPathsToUrlsRule.cs
@@ -0,0 +1,54 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+using Microsoft.AspNetCore.Rewrite;
+
+namespace StardewModdingAPI.Web.Framework.RedirectRules
+{
+ /// Redirect paths to URLs if they match a condition.
+ internal class RedirectPathsToUrlsRule : RedirectMatchRule
+ {
+ /*********
+ ** Fields
+ *********/
+ /// Regex patterns matching the current URL mapped to the resulting redirect URL.
+ private readonly IDictionary Map;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// Construct an instance.
+ /// Regex patterns matching the current URL mapped to the resulting redirect URL.
+ public RedirectPathsToUrlsRule(IDictionary map)
+ {
+ this.Map = map.ToDictionary(
+ p => new Regex(p.Key, RegexOptions.IgnoreCase | RegexOptions.Compiled),
+ p => p.Value
+ );
+ }
+
+
+ /*********
+ ** Protected methods
+ *********/
+ /// Get the new redirect URL.
+ /// The rewrite context.
+ /// Returns the redirect URL, or null if the redirect doesn't apply.
+ protected override string GetNewUrl(RewriteContext context)
+ {
+ string path = context.HttpContext.Request.Path.Value;
+
+ if (!string.IsNullOrWhiteSpace(path))
+ {
+ foreach ((Regex pattern, string url) in this.Map)
+ {
+ if (pattern.IsMatch(path))
+ return pattern.Replace(path, url);
+ }
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/SMAPI.Web/Framework/RedirectRules/RedirectToHttpsRule.cs b/src/SMAPI.Web/Framework/RedirectRules/RedirectToHttpsRule.cs
new file mode 100644
index 00000000..2a503ae3
--- /dev/null
+++ b/src/SMAPI.Web/Framework/RedirectRules/RedirectToHttpsRule.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Net;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Rewrite;
+
+namespace StardewModdingAPI.Web.Framework.RedirectRules
+{
+ /// Redirect requests to HTTPS.
+ internal class RedirectToHttpsRule : RedirectMatchRule
+ {
+ /*********
+ ** Fields
+ *********/
+ /// Matches requests which should be ignored.
+ private readonly Func Except;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// Construct an instance.
+ /// Matches requests which should be ignored.
+ public RedirectToHttpsRule(Func except = null)
+ {
+ this.Except = except ?? (req => false);
+ this.StatusCode = HttpStatusCode.RedirectKeepVerb;
+ }
+
+
+ /*********
+ ** Protected methods
+ *********/
+ /// Get the new redirect URL.
+ /// The rewrite context.
+ /// Returns the redirect URL, or null if the redirect doesn't apply.
+ protected override string GetNewUrl(RewriteContext context)
+ {
+ HttpRequest request = context.HttpContext.Request;
+ if (request.IsHttps || this.Except(request))
+ return null;
+
+ UriBuilder uri = this.GetUrl(request);
+ uri.Scheme = "https";
+ return uri.ToString();
+ }
+ }
+}
diff --git a/src/SMAPI.Web/Framework/RewriteRules/ConditionalRedirectToHttpsRule.cs b/src/SMAPI.Web/Framework/RewriteRules/ConditionalRedirectToHttpsRule.cs
deleted file mode 100644
index 36effd82..00000000
--- a/src/SMAPI.Web/Framework/RewriteRules/ConditionalRedirectToHttpsRule.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using System;
-using System.Net;
-using System.Text;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Rewrite;
-
-namespace StardewModdingAPI.Web.Framework.RewriteRules
-{
- /// Redirect requests to HTTPS.
- /// Derived from and .
- internal class ConditionalRedirectToHttpsRule : IRule
- {
- /*********
- ** Fields
- *********/
- /// A predicate which indicates when the rule should be applied.
- private readonly Func ShouldRewrite;
-
-
- /*********
- ** Public methods
- *********/
- /// Construct an instance.
- /// A predicate which indicates when the rule should be applied.
- public ConditionalRedirectToHttpsRule(Func shouldRewrite = null)
- {
- this.ShouldRewrite = shouldRewrite ?? (req => true);
- }
-
- /// Applies the rule. Implementations of ApplyRule should set the value for (defaults to RuleResult.ContinueRules).
- /// The rewrite context.
- public void ApplyRule(RewriteContext context)
- {
- HttpRequest request = context.HttpContext.Request;
-
- // check condition
- if (this.IsSecure(request) || !this.ShouldRewrite(request))
- return;
-
- // redirect request
- HttpResponse response = context.HttpContext.Response;
- response.StatusCode = (int)HttpStatusCode.RedirectKeepVerb;
- response.Headers["Location"] = new StringBuilder()
- .Append("https://")
- .Append(request.Host.Host)
- .Append(request.PathBase)
- .Append(request.Path)
- .Append(request.QueryString)
- .ToString();
- context.Result = RuleResult.EndResponse;
- }
-
- /// Get whether the request was received over HTTPS.
- /// The request to check.
- public bool IsSecure(HttpRequest request)
- {
- return
- request.IsHttps // HTTPS to server
- || string.Equals(request.Headers["x-forwarded-proto"], "HTTPS", StringComparison.OrdinalIgnoreCase); // HTTPS to AWS load balancer
- }
- }
-}
diff --git a/src/SMAPI.Web/Framework/RewriteRules/RedirectToUrlRule.cs b/src/SMAPI.Web/Framework/RewriteRules/RedirectToUrlRule.cs
deleted file mode 100644
index ab9e019c..00000000
--- a/src/SMAPI.Web/Framework/RewriteRules/RedirectToUrlRule.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using System;
-using System.Net;
-using System.Text.RegularExpressions;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Rewrite;
-
-namespace StardewModdingAPI.Web.Framework.RewriteRules
-{
- /// Redirect requests to an external URL if they match a condition.
- internal class RedirectToUrlRule : IRule
- {
- /*********
- ** Fields
- *********/
- /// Get the new URL to which to redirect (or null to skip).
- private readonly Func NewUrl;
-
-
- /*********
- ** Public methods
- *********/
- /// Construct an instance.
- /// A predicate which indicates when the rule should be applied.
- /// The new URL to which to redirect.
- public RedirectToUrlRule(Func shouldRewrite, string url)
- {
- this.NewUrl = req => shouldRewrite(req) ? url : null;
- }
-
- /// Construct an instance.
- /// A case-insensitive regex to match against the path.
- /// The external URL.
- public RedirectToUrlRule(string pathRegex, string url)
- {
- Regex regex = new Regex(pathRegex, RegexOptions.IgnoreCase | RegexOptions.Compiled);
- this.NewUrl = req => req.Path.HasValue ? regex.Replace(req.Path.Value, url) : null;
- }
-
- /// Applies the rule. Implementations of ApplyRule should set the value for (defaults to RuleResult.ContinueRules).
- /// The rewrite context.
- public void ApplyRule(RewriteContext context)
- {
- HttpRequest request = context.HttpContext.Request;
-
- // check rewrite
- string newUrl = this.NewUrl(request);
- if (newUrl == null || newUrl == request.Path.Value)
- return;
-
- // redirect request
- HttpResponse response = context.HttpContext.Response;
- response.StatusCode = (int)HttpStatusCode.Redirect;
- response.Headers["Location"] = newUrl;
- context.Result = RuleResult.EndResponse;
- }
- }
-}
diff --git a/src/SMAPI.Web/Startup.cs b/src/SMAPI.Web/Startup.cs
index ddfae166..dee2edc2 100644
--- a/src/SMAPI.Web/Startup.cs
+++ b/src/SMAPI.Web/Startup.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Net;
using Hangfire;
using Hangfire.MemoryStorage;
using Hangfire.Mongo;
@@ -27,7 +28,7 @@ using StardewModdingAPI.Web.Framework.Clients.Nexus;
using StardewModdingAPI.Web.Framework.Clients.Pastebin;
using StardewModdingAPI.Web.Framework.Compression;
using StardewModdingAPI.Web.Framework.ConfigModels;
-using StardewModdingAPI.Web.Framework.RewriteRules;
+using StardewModdingAPI.Web.Framework.RedirectRules;
using StardewModdingAPI.Web.Framework.Storage;
namespace StardewModdingAPI.Web
@@ -270,26 +271,49 @@ namespace StardewModdingAPI.Web
/// Get the redirect rules to apply.
private RewriteOptions GetRedirectRules()
{
- var redirects = new RewriteOptions();
+ var redirects = new RewriteOptions()
+ // shortcut paths
+ .Add(new RedirectPathsToUrlsRule(new Dictionary
+ {
+ [@"^/3\.0\.?$"] = "https://stardewvalleywiki.com/Modding:Migrate_to_SMAPI_3.0",
+ [@"^/(?:buildmsg|package)(?:/?(.*))$"] = "https://github.com/Pathoschild/SMAPI/blob/develop/docs/technical/mod-package.md#$1", // buildmsg deprecated, remove when SDV 1.4 is released
+ [@"^/community\.?$"] = "https://stardewvalleywiki.com/Modding:Community",
+ [@"^/compat\.?$"] = "https://smapi.io/mods",
+ [@"^/docs\.?$"] = "https://stardewvalleywiki.com/Modding:Index",
+ [@"^/install\.?$"] = "https://stardewvalleywiki.com/Modding:Player_Guide/Getting_Started#Install_SMAPI",
+ [@"^/troubleshoot(.*)$"] = "https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting$1",
+ [@"^/xnb\.?$"] = "https://stardewvalleywiki.com/Modding:Using_XNB_mods"
+ }))
- // redirect to HTTPS (except API for Linux/Mac Mono compatibility)
- redirects.Add(new ConditionalRedirectToHttpsRule(
- shouldRewrite: req =>
- req.Host.Host != "localhost"
- && !req.Path.StartsWithSegments("/api")
- ));
+ // legacy paths
+ .Add(new RedirectPathsToUrlsRule(this.GetLegacyPathRedirects()))
- // shortcut redirects
- redirects.Add(new RedirectToUrlRule(@"^/3\.0\.?$", "https://stardewvalleywiki.com/Modding:Migrate_to_SMAPI_3.0"));
- redirects.Add(new RedirectToUrlRule(@"^/(?:buildmsg|package)(?:/?(.*))$", "https://github.com/Pathoschild/SMAPI/blob/develop/docs/technical/mod-package.md#$1")); // buildmsg deprecated, remove when SDV 1.4 is released
- redirects.Add(new RedirectToUrlRule(@"^/community\.?$", "https://stardewvalleywiki.com/Modding:Community"));
- redirects.Add(new RedirectToUrlRule(@"^/compat\.?$", "https://smapi.io/mods"));
- redirects.Add(new RedirectToUrlRule(@"^/docs\.?$", "https://stardewvalleywiki.com/Modding:Index"));
- redirects.Add(new RedirectToUrlRule(@"^/install\.?$", "https://stardewvalleywiki.com/Modding:Player_Guide/Getting_Started#Install_SMAPI"));
- redirects.Add(new RedirectToUrlRule(@"^/troubleshoot(.*)$", "https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting$1"));
- redirects.Add(new RedirectToUrlRule(@"^/xnb\.?$", "https://stardewvalleywiki.com/Modding:Using_XNB_mods"));
+ // subdomains
+ .Add(new RedirectHostsToUrlsRule(HttpStatusCode.PermanentRedirect, host => host switch
+ {
+ "api.smapi.io" => "smapi.io/api",
+ "json.smapi.io" => "smapi.io/json",
+ "log.smapi.io" => "smapi.io/log",
+ "mods.smapi.io" => "smapi.io/mods",
+ _ => host.EndsWith(".smapi.io")
+ ? "smapi.io"
+ : null
+ }))
- // redirect legacy canimod.com URLs
+ // redirect to HTTPS (except API for Linux/Mac Mono compatibility)
+ .Add(
+ new RedirectToHttpsRule(except: req => req.Host.Host == "localhost" || req.Path.StartsWithSegments("/api"))
+ );
+
+ return redirects;
+ }
+
+ /// Get the redirects for legacy paths that have been moved elsewhere.
+ private IDictionary GetLegacyPathRedirects()
+ {
+ var redirects = new Dictionary();
+
+ // canimod.com => wiki
var wikiRedirects = new Dictionary
{
["Modding:Index#Migration_guides"] = new[] { "^/for-devs/updating-a-smapi-mod", "^/guides/updating-a-smapi-mod" },
@@ -306,7 +330,7 @@ namespace StardewModdingAPI.Web
foreach ((string page, string[] patterns) in wikiRedirects)
{
foreach (string pattern in patterns)
- redirects.Add(new RedirectToUrlRule(pattern, "https://stardewvalleywiki.com/" + page));
+ redirects.Add(pattern, "https://stardewvalleywiki.com/" + page);
}
return redirects;
diff --git a/src/SMAPI.sln b/src/SMAPI.sln
index f9c537c4..92b0cd2c 100644
--- a/src/SMAPI.sln
+++ b/src/SMAPI.sln
@@ -77,8 +77,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Toolkit.CoreInterface
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Web", "SMAPI.Web\SMAPI.Web.csproj", "{80EFD92F-728F-41E0-8A5B-9F6F49A91899}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Web.LegacyRedirects", "SMAPI.Web.LegacyRedirects\SMAPI.Web.LegacyRedirects.csproj", "{159AA5A5-35C2-488C-B23F-1613C80594AE}"
-EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5
@@ -138,10 +136,6 @@ Global
{80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Debug|Any CPU.Build.0 = Debug|Any CPU
{80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.ActiveCfg = Release|Any CPU
{80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.Build.0 = Release|Any CPU
- {159AA5A5-35C2-488C-B23F-1613C80594AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {159AA5A5-35C2-488C-B23F-1613C80594AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {159AA5A5-35C2-488C-B23F-1613C80594AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {159AA5A5-35C2-488C-B23F-1613C80594AE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE