make console colors configurable
This commit is contained in:
parent
e6edf8adc7
commit
1b5055dfaa
|
@ -43,6 +43,7 @@ For modders:
|
||||||
* Improved mod scanning:
|
* Improved mod scanning:
|
||||||
* Now ignores metadata files and folders (like `__MACOSX` and `__folder_managed_by_vortex`) and content files (like `.txt` or `.png`), which avoids missing-manifest errors in some common cases.
|
* Now ignores metadata files and folders (like `__MACOSX` and `__folder_managed_by_vortex`) and content files (like `.txt` or `.png`), which avoids missing-manifest errors in some common cases.
|
||||||
* Now detects XNB mods more accurately, and consolidates multi-folder XNB mods in logged messages.
|
* Now detects XNB mods more accurately, and consolidates multi-folder XNB mods in logged messages.
|
||||||
|
* Added support for configuring console colors via `smapi-internal/config.json` (intended for players with unusual consoles).
|
||||||
* Save Backup now works in the background, to avoid affecting startup time for players with a large number of saves.
|
* Save Backup now works in the background, to avoid affecting startup time for players with a large number of saves.
|
||||||
* The installer now recognises custom game paths stored in `stardewvalley.targets`.
|
* The installer now recognises custom game paths stored in `stardewvalley.targets`.
|
||||||
* Duplicate-mod errors now show the mod version in each folder.
|
* Duplicate-mod errors now show the mod version in each folder.
|
||||||
|
|
|
@ -100,7 +100,7 @@ namespace StardewModdingApi.Installer
|
||||||
public InteractiveInstaller(string bundlePath)
|
public InteractiveInstaller(string bundlePath)
|
||||||
{
|
{
|
||||||
this.BundlePath = bundlePath;
|
this.BundlePath = bundlePath;
|
||||||
this.ConsoleWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform(), MonitorColorScheme.AutoDetect);
|
this.ConsoleWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Run the install or uninstall script.</summary>
|
/// <summary>Run the install or uninstall script.</summary>
|
||||||
|
@ -217,8 +217,8 @@ namespace StardewModdingApi.Installer
|
||||||
** show theme selector
|
** show theme selector
|
||||||
****/
|
****/
|
||||||
// get theme writers
|
// get theme writers
|
||||||
var lightBackgroundWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform(), MonitorColorScheme.LightBackground);
|
var lightBackgroundWriter = new ColorfulConsoleWriter(platform, ColorfulConsoleWriter.GetDefaultColorSchemeConfig(MonitorColorScheme.LightBackground));
|
||||||
var darkBackgroundWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform(), MonitorColorScheme.DarkBackground);
|
var darkBackgroundWriter = new ColorfulConsoleWriter(platform, ColorfulConsoleWriter.GetDefaultColorSchemeConfig(MonitorColorScheme.DarkBackground));
|
||||||
|
|
||||||
// print question
|
// print question
|
||||||
this.PrintPlain("Which text looks more readable?");
|
this.PrintPlain("Which text looks more readable?");
|
||||||
|
@ -470,7 +470,7 @@ namespace StardewModdingApi.Installer
|
||||||
{
|
{
|
||||||
string text = File
|
string text = File
|
||||||
.ReadAllText(paths.ApiConfigPath)
|
.ReadAllText(paths.ApiConfigPath)
|
||||||
.Replace(@"""ColorScheme"": ""AutoDetect""", $@"""ColorScheme"": ""{scheme}""");
|
.Replace(@"""UseScheme"": ""AutoDetect""", $@"""UseScheme"": ""{scheme}""");
|
||||||
File.WriteAllText(paths.ApiConfigPath, text);
|
File.WriteAllText(paths.ApiConfigPath, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Internal.ConsoleWriting
|
||||||
|
{
|
||||||
|
/// <summary>The console color scheme options.</summary>
|
||||||
|
internal class ColorSchemeConfig
|
||||||
|
{
|
||||||
|
/// <summary>The default color scheme ID to use, or <see cref="MonitorColorScheme.AutoDetect"/> to select one automatically.</summary>
|
||||||
|
public MonitorColorScheme UseScheme { get; set; }
|
||||||
|
|
||||||
|
/// <summary>The available console color schemes.</summary>
|
||||||
|
public IDictionary<MonitorColorScheme, IDictionary<ConsoleLogLevel, ConsoleColor>> Schemes { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,11 +22,16 @@ namespace StardewModdingAPI.Internal.ConsoleWriting
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Construct an instance.</summary>
|
/// <summary>Construct an instance.</summary>
|
||||||
/// <param name="platform">The target platform.</param>
|
/// <param name="platform">The target platform.</param>
|
||||||
/// <param name="colorScheme">The console color scheme to use.</param>
|
public ColorfulConsoleWriter(Platform platform)
|
||||||
public ColorfulConsoleWriter(Platform platform, MonitorColorScheme colorScheme)
|
: this(platform, ColorfulConsoleWriter.GetDefaultColorSchemeConfig(MonitorColorScheme.AutoDetect)) { }
|
||||||
|
|
||||||
|
/// <summary>Construct an instance.</summary>
|
||||||
|
/// <param name="platform">The target platform.</param>
|
||||||
|
/// <param name="colorConfig">The colors to use for text written to the SMAPI console.</param>
|
||||||
|
public ColorfulConsoleWriter(Platform platform, ColorSchemeConfig colorConfig)
|
||||||
{
|
{
|
||||||
this.SupportsColor = this.TestColorSupport();
|
this.SupportsColor = this.TestColorSupport();
|
||||||
this.Colors = this.GetConsoleColorScheme(platform, colorScheme);
|
this.Colors = this.GetConsoleColorScheme(platform, colorConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Write a message line to the log.</summary>
|
/// <summary>Write a message line to the log.</summary>
|
||||||
|
@ -54,6 +59,40 @@ namespace StardewModdingAPI.Internal.ConsoleWriting
|
||||||
Console.WriteLine(message);
|
Console.WriteLine(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Get the default color scheme config for cases where it's not configurable (e.g. the installer).</summary>
|
||||||
|
/// <param name="useScheme">The default color scheme ID to use, or <see cref="MonitorColorScheme.AutoDetect"/> to select one automatically.</param>
|
||||||
|
/// <remarks>The colors here should be kept in sync with the SMAPI config file.</remarks>
|
||||||
|
public static ColorSchemeConfig GetDefaultColorSchemeConfig(MonitorColorScheme useScheme)
|
||||||
|
{
|
||||||
|
return new ColorSchemeConfig
|
||||||
|
{
|
||||||
|
UseScheme = useScheme,
|
||||||
|
Schemes = new Dictionary<MonitorColorScheme, IDictionary<ConsoleLogLevel, ConsoleColor>>
|
||||||
|
{
|
||||||
|
[MonitorColorScheme.DarkBackground] = new Dictionary<ConsoleLogLevel, ConsoleColor>
|
||||||
|
{
|
||||||
|
[ConsoleLogLevel.Trace] = ConsoleColor.DarkGray,
|
||||||
|
[ConsoleLogLevel.Debug] = ConsoleColor.DarkGray,
|
||||||
|
[ConsoleLogLevel.Info] = ConsoleColor.White,
|
||||||
|
[ConsoleLogLevel.Warn] = ConsoleColor.Yellow,
|
||||||
|
[ConsoleLogLevel.Error] = ConsoleColor.Red,
|
||||||
|
[ConsoleLogLevel.Alert] = ConsoleColor.Magenta,
|
||||||
|
[ConsoleLogLevel.Success] = ConsoleColor.DarkGreen
|
||||||
|
},
|
||||||
|
[MonitorColorScheme.LightBackground] = new Dictionary<ConsoleLogLevel, ConsoleColor>
|
||||||
|
{
|
||||||
|
[ConsoleLogLevel.Trace] = ConsoleColor.DarkGray,
|
||||||
|
[ConsoleLogLevel.Debug] = ConsoleColor.DarkGray,
|
||||||
|
[ConsoleLogLevel.Info] = ConsoleColor.Black,
|
||||||
|
[ConsoleLogLevel.Warn] = ConsoleColor.DarkYellow,
|
||||||
|
[ConsoleLogLevel.Error] = ConsoleColor.Red,
|
||||||
|
[ConsoleLogLevel.Alert] = ConsoleColor.DarkMagenta,
|
||||||
|
[ConsoleLogLevel.Success] = ConsoleColor.DarkGreen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
** Private methods
|
** Private methods
|
||||||
|
@ -74,47 +113,22 @@ namespace StardewModdingAPI.Internal.ConsoleWriting
|
||||||
|
|
||||||
/// <summary>Get the color scheme to use for the current console.</summary>
|
/// <summary>Get the color scheme to use for the current console.</summary>
|
||||||
/// <param name="platform">The target platform.</param>
|
/// <param name="platform">The target platform.</param>
|
||||||
/// <param name="colorScheme">The console color scheme to use.</param>
|
/// <param name="colorConfig">The colors to use for text written to the SMAPI console.</param>
|
||||||
private IDictionary<ConsoleLogLevel, ConsoleColor> GetConsoleColorScheme(Platform platform, MonitorColorScheme colorScheme)
|
private IDictionary<ConsoleLogLevel, ConsoleColor> GetConsoleColorScheme(Platform platform, ColorSchemeConfig colorConfig)
|
||||||
{
|
{
|
||||||
// auto detect color scheme
|
// get color scheme ID
|
||||||
if (colorScheme == MonitorColorScheme.AutoDetect)
|
MonitorColorScheme schemeID = colorConfig.UseScheme;
|
||||||
|
if (schemeID == MonitorColorScheme.AutoDetect)
|
||||||
{
|
{
|
||||||
colorScheme = platform == Platform.Mac
|
schemeID = platform == Platform.Mac
|
||||||
? MonitorColorScheme.LightBackground // MacOS doesn't provide console background color info, but it's usually white.
|
? MonitorColorScheme.LightBackground // MacOS doesn't provide console background color info, but it's usually white.
|
||||||
: ColorfulConsoleWriter.IsDark(Console.BackgroundColor) ? MonitorColorScheme.DarkBackground : MonitorColorScheme.LightBackground;
|
: ColorfulConsoleWriter.IsDark(Console.BackgroundColor) ? MonitorColorScheme.DarkBackground : MonitorColorScheme.LightBackground;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get colors for scheme
|
// get colors for scheme
|
||||||
switch (colorScheme)
|
return colorConfig.Schemes.TryGetValue(schemeID, out IDictionary<ConsoleLogLevel, ConsoleColor> scheme)
|
||||||
{
|
? scheme
|
||||||
case MonitorColorScheme.DarkBackground:
|
: throw new NotSupportedException($"Unknown color scheme '{schemeID}'.");
|
||||||
return new Dictionary<ConsoleLogLevel, ConsoleColor>
|
|
||||||
{
|
|
||||||
[ConsoleLogLevel.Trace] = ConsoleColor.DarkGray,
|
|
||||||
[ConsoleLogLevel.Debug] = ConsoleColor.DarkGray,
|
|
||||||
[ConsoleLogLevel.Info] = ConsoleColor.White,
|
|
||||||
[ConsoleLogLevel.Warn] = ConsoleColor.Yellow,
|
|
||||||
[ConsoleLogLevel.Error] = ConsoleColor.Red,
|
|
||||||
[ConsoleLogLevel.Alert] = ConsoleColor.Magenta,
|
|
||||||
[ConsoleLogLevel.Success] = ConsoleColor.DarkGreen
|
|
||||||
};
|
|
||||||
|
|
||||||
case MonitorColorScheme.LightBackground:
|
|
||||||
return new Dictionary<ConsoleLogLevel, ConsoleColor>
|
|
||||||
{
|
|
||||||
[ConsoleLogLevel.Trace] = ConsoleColor.DarkGray,
|
|
||||||
[ConsoleLogLevel.Debug] = ConsoleColor.DarkGray,
|
|
||||||
[ConsoleLogLevel.Info] = ConsoleColor.Black,
|
|
||||||
[ConsoleLogLevel.Warn] = ConsoleColor.DarkYellow,
|
|
||||||
[ConsoleLogLevel.Error] = ConsoleColor.Red,
|
|
||||||
[ConsoleLogLevel.Alert] = ConsoleColor.DarkMagenta,
|
|
||||||
[ConsoleLogLevel.Success] = ConsoleColor.DarkGreen
|
|
||||||
};
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new NotSupportedException($"Unknown color scheme '{colorScheme}'.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Get whether a console color should be considered dark, which is subjectively defined as 'white looks better than black on this text'.</summary>
|
/// <summary>Get whether a console color should be considered dark, which is subjectively defined as 'white looks better than black on this text'.</summary>
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)ConsoleWriting\ColorfulConsoleWriter.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)ConsoleWriting\ColorfulConsoleWriter.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)ConsoleWriting\LogLevel.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)ConsoleWriting\ColorSchemeConfig.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)ConsoleWriting\ConsoleLogLevel.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)ConsoleWriting\MonitorColorScheme.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)ConsoleWriting\MonitorColorScheme.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -67,8 +67,8 @@ namespace StardewModdingAPI.Framework.Models
|
||||||
/// <summary>Whether to generate a file in the mods folder with detailed metadata about the detected mods.</summary>
|
/// <summary>Whether to generate a file in the mods folder with detailed metadata about the detected mods.</summary>
|
||||||
public bool DumpMetadata { get; set; }
|
public bool DumpMetadata { get; set; }
|
||||||
|
|
||||||
/// <summary>The console color scheme to use.</summary>
|
/// <summary>The colors to use for text written to the SMAPI console.</summary>
|
||||||
public MonitorColorScheme ColorScheme { get; set; }
|
public ColorSchemeConfig ConsoleColors { get; set; }
|
||||||
|
|
||||||
/// <summary>The mod IDs SMAPI should ignore when performing update checks or validating update keys.</summary>
|
/// <summary>The mod IDs SMAPI should ignore when performing update checks or validating update keys.</summary>
|
||||||
public string[] SuppressUpdateChecks { get; set; }
|
public string[] SuppressUpdateChecks { get; set; }
|
||||||
|
|
|
@ -50,9 +50,9 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <param name="source">The name of the module which logs messages using this instance.</param>
|
/// <param name="source">The name of the module which logs messages using this instance.</param>
|
||||||
/// <param name="consoleInterceptor">Intercepts access to the console output.</param>
|
/// <param name="consoleInterceptor">Intercepts access to the console output.</param>
|
||||||
/// <param name="logFile">The log file to which to write messages.</param>
|
/// <param name="logFile">The log file to which to write messages.</param>
|
||||||
/// <param name="colorScheme">The console color scheme to use.</param>
|
/// <param name="colorConfig">The colors to use for text written to the SMAPI console.</param>
|
||||||
/// <param name="isVerbose">Whether verbose logging is enabled. This enables more detailed diagnostic messages than are normally needed.</param>
|
/// <param name="isVerbose">Whether verbose logging is enabled. This enables more detailed diagnostic messages than are normally needed.</param>
|
||||||
public Monitor(string source, ConsoleInterceptionManager consoleInterceptor, LogFileManager logFile, MonitorColorScheme colorScheme, bool isVerbose)
|
public Monitor(string source, ConsoleInterceptionManager consoleInterceptor, LogFileManager logFile, ColorSchemeConfig colorConfig, bool isVerbose)
|
||||||
{
|
{
|
||||||
// validate
|
// validate
|
||||||
if (string.IsNullOrWhiteSpace(source))
|
if (string.IsNullOrWhiteSpace(source))
|
||||||
|
@ -61,7 +61,7 @@ namespace StardewModdingAPI.Framework
|
||||||
// initialize
|
// initialize
|
||||||
this.Source = source;
|
this.Source = source;
|
||||||
this.LogFile = logFile ?? throw new ArgumentNullException(nameof(logFile), "The log file manager cannot be null.");
|
this.LogFile = logFile ?? throw new ArgumentNullException(nameof(logFile), "The log file manager cannot be null.");
|
||||||
this.ConsoleWriter = new ColorfulConsoleWriter(Constants.Platform, colorScheme);
|
this.ConsoleWriter = new ColorfulConsoleWriter(Constants.Platform, colorConfig);
|
||||||
this.ConsoleInterceptor = consoleInterceptor;
|
this.ConsoleInterceptor = consoleInterceptor;
|
||||||
this.IsVerbose = isVerbose;
|
this.IsVerbose = isVerbose;
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,7 +143,7 @@ namespace StardewModdingAPI.Framework
|
||||||
// init basics
|
// init basics
|
||||||
this.Settings = JsonConvert.DeserializeObject<SConfig>(File.ReadAllText(Constants.ApiConfigPath));
|
this.Settings = JsonConvert.DeserializeObject<SConfig>(File.ReadAllText(Constants.ApiConfigPath));
|
||||||
this.LogFile = new LogFileManager(logPath);
|
this.LogFile = new LogFileManager(logPath);
|
||||||
this.Monitor = new Monitor("SMAPI", this.ConsoleManager, this.LogFile, this.Settings.ColorScheme, this.Settings.VerboseLogging)
|
this.Monitor = new Monitor("SMAPI", this.ConsoleManager, this.LogFile, this.Settings.ConsoleColors, this.Settings.VerboseLogging)
|
||||||
{
|
{
|
||||||
WriteToConsole = writeToConsole,
|
WriteToConsole = writeToConsole,
|
||||||
ShowTraceInConsole = this.Settings.DeveloperMode,
|
ShowTraceInConsole = this.Settings.DeveloperMode,
|
||||||
|
@ -1351,7 +1351,7 @@ namespace StardewModdingAPI.Framework
|
||||||
/// <param name="name">The name of the module which will log messages with this instance.</param>
|
/// <param name="name">The name of the module which will log messages with this instance.</param>
|
||||||
private Monitor GetSecondaryMonitor(string name)
|
private Monitor GetSecondaryMonitor(string name)
|
||||||
{
|
{
|
||||||
return new Monitor(name, this.ConsoleManager, this.LogFile, this.Settings.ColorScheme, this.Settings.VerboseLogging)
|
return new Monitor(name, this.ConsoleManager, this.LogFile, this.Settings.ConsoleColors, this.Settings.VerboseLogging)
|
||||||
{
|
{
|
||||||
WriteToConsole = this.Monitor.WriteToConsole,
|
WriteToConsole = this.Monitor.WriteToConsole,
|
||||||
ShowTraceInConsole = this.Settings.DeveloperMode,
|
ShowTraceInConsole = this.Settings.DeveloperMode,
|
||||||
|
|
|
@ -10,12 +10,9 @@ The default values are mirrored in StardewModdingAPI.Framework.Models.SConfig to
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The console color theme to use. The possible values are:
|
* Whether SMAPI should log more information about the game context.
|
||||||
* - AutoDetect: SMAPI will assume a light background on Mac, and detect the background color automatically on Linux or Windows.
|
|
||||||
* - LightBackground: use darker text colors that look better on a white or light background.
|
|
||||||
* - DarkBackground: use lighter text colors that look better on a black or dark background.
|
|
||||||
*/
|
*/
|
||||||
"ColorScheme": "AutoDetect",
|
"VerboseLogging": false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether SMAPI should check for newer versions of SMAPI and mods when you load the game. If new
|
* Whether SMAPI should check for newer versions of SMAPI and mods when you load the game. If new
|
||||||
|
@ -57,11 +54,6 @@ The default values are mirrored in StardewModdingAPI.Framework.Models.SConfig to
|
||||||
*/
|
*/
|
||||||
"WebApiBaseUrl": "https://api.smapi.io",
|
"WebApiBaseUrl": "https://api.smapi.io",
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether SMAPI should log more information about the game context.
|
|
||||||
*/
|
|
||||||
"VerboseLogging": false,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether SMAPI should log network traffic (may be very verbose). Best combined with VerboseLogging, which includes network metadata.
|
* Whether SMAPI should log network traffic (may be very verbose). Best combined with VerboseLogging, which includes network metadata.
|
||||||
*/
|
*/
|
||||||
|
@ -73,6 +65,45 @@ The default values are mirrored in StardewModdingAPI.Framework.Models.SConfig to
|
||||||
*/
|
*/
|
||||||
"DumpMetadata": false,
|
"DumpMetadata": false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The colors to use for text written to the SMAPI console.
|
||||||
|
*
|
||||||
|
* The possible values for 'UseScheme' are:
|
||||||
|
* - AutoDetect: SMAPI will assume a light background on Mac, and detect the background color
|
||||||
|
* automatically on Linux or Windows.
|
||||||
|
* - LightBackground: use darker text colors that look better on a white or light background.
|
||||||
|
* - DarkBackground: use lighter text colors that look better on a black or dark background.
|
||||||
|
*
|
||||||
|
* For available color codes, see https://docs.microsoft.com/en-us/dotnet/api/system.consolecolor.
|
||||||
|
*
|
||||||
|
* (These values are synched with ColorfulConsoleWriter.GetDefaultColorSchemeConfig in the
|
||||||
|
* SMAPI code.)
|
||||||
|
*/
|
||||||
|
"ConsoleColors": {
|
||||||
|
"UseScheme": "AutoDetect",
|
||||||
|
|
||||||
|
"Schemes": {
|
||||||
|
"DarkBackground": {
|
||||||
|
"Trace": "DarkGray",
|
||||||
|
"Debug": "DarkGray",
|
||||||
|
"Info": "White",
|
||||||
|
"Warn": "Yellow",
|
||||||
|
"Error": "Red",
|
||||||
|
"Alert": "Magenta",
|
||||||
|
"Success": "DarkGreen"
|
||||||
|
},
|
||||||
|
"LightBackground": {
|
||||||
|
"Trace": "DarkGray",
|
||||||
|
"Debug": "DarkGray",
|
||||||
|
"Info": "Black",
|
||||||
|
"Warn": "DarkYellow",
|
||||||
|
"Error": "Red",
|
||||||
|
"Alert": "DarkMagenta",
|
||||||
|
"Success": "DarkGreen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The mod IDs SMAPI should ignore when performing update checks or validating update keys.
|
* The mod IDs SMAPI should ignore when performing update checks or validating update keys.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue