Implement GetRegionCode and add the RegionCode to settings (#999)
This implement `GetRegionCode` accordingly to RE. I've added a setting in the GUI and a field in the Configuration file with a way to update the Configuration file if needed.
This commit is contained in:
parent
561d64e5bf
commit
32d3f3f690
12 changed files with 156 additions and 6 deletions
|
@ -73,6 +73,11 @@ namespace Ryujinx.Configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Language SystemLanguage { get; set; }
|
public Language SystemLanguage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Change System Region
|
||||||
|
/// </summary>
|
||||||
|
public Region SystemRegion { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables or disables Docked Mode
|
/// Enables or disables Docked Mode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -148,6 +148,11 @@ namespace Ryujinx.Configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ReactiveObject<Language> Language { get; private set; }
|
public ReactiveObject<Language> Language { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Change System Region
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<Region> Region { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables or disables Docked Mode
|
/// Enables or disables Docked Mode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -176,6 +181,7 @@ namespace Ryujinx.Configuration
|
||||||
public SystemSection()
|
public SystemSection()
|
||||||
{
|
{
|
||||||
Language = new ReactiveObject<Language>();
|
Language = new ReactiveObject<Language>();
|
||||||
|
Region = new ReactiveObject<Region>();
|
||||||
EnableDockedMode = new ReactiveObject<bool>();
|
EnableDockedMode = new ReactiveObject<bool>();
|
||||||
EnableMulticoreScheduling = new ReactiveObject<bool>();
|
EnableMulticoreScheduling = new ReactiveObject<bool>();
|
||||||
EnableFsIntegrityChecks = new ReactiveObject<bool>();
|
EnableFsIntegrityChecks = new ReactiveObject<bool>();
|
||||||
|
@ -289,7 +295,7 @@ namespace Ryujinx.Configuration
|
||||||
{
|
{
|
||||||
ConfigurationFileFormat configurationFile = new ConfigurationFileFormat
|
ConfigurationFileFormat configurationFile = new ConfigurationFileFormat
|
||||||
{
|
{
|
||||||
Version = 1,
|
Version = 2,
|
||||||
GraphicsShadersDumpPath = Graphics.ShadersDumpPath,
|
GraphicsShadersDumpPath = Graphics.ShadersDumpPath,
|
||||||
LoggingEnableDebug = Logger.EnableDebug,
|
LoggingEnableDebug = Logger.EnableDebug,
|
||||||
LoggingEnableStub = Logger.EnableStub,
|
LoggingEnableStub = Logger.EnableStub,
|
||||||
|
@ -301,6 +307,7 @@ namespace Ryujinx.Configuration
|
||||||
LoggingFilteredClasses = Logger.FilteredClasses,
|
LoggingFilteredClasses = Logger.FilteredClasses,
|
||||||
EnableFileLog = Logger.EnableFileLog,
|
EnableFileLog = Logger.EnableFileLog,
|
||||||
SystemLanguage = System.Language,
|
SystemLanguage = System.Language,
|
||||||
|
SystemRegion = System.Region,
|
||||||
DockedMode = System.EnableDockedMode,
|
DockedMode = System.EnableDockedMode,
|
||||||
EnableDiscordIntegration = EnableDiscordIntegration,
|
EnableDiscordIntegration = EnableDiscordIntegration,
|
||||||
EnableVsync = Graphics.EnableVsync,
|
EnableVsync = Graphics.EnableVsync,
|
||||||
|
@ -346,6 +353,7 @@ namespace Ryujinx.Configuration
|
||||||
Logger.FilteredClasses.Value = new LogClass[] { };
|
Logger.FilteredClasses.Value = new LogClass[] { };
|
||||||
Logger.EnableFileLog.Value = true;
|
Logger.EnableFileLog.Value = true;
|
||||||
System.Language.Value = Language.AmericanEnglish;
|
System.Language.Value = Language.AmericanEnglish;
|
||||||
|
System.Region.Value = Region.USA;
|
||||||
System.EnableDockedMode.Value = false;
|
System.EnableDockedMode.Value = false;
|
||||||
EnableDiscordIntegration.Value = true;
|
EnableDiscordIntegration.Value = true;
|
||||||
Graphics.EnableVsync.Value = true;
|
Graphics.EnableVsync.Value = true;
|
||||||
|
@ -440,9 +448,11 @@ namespace Ryujinx.Configuration
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Load(ConfigurationFileFormat configurationFileFormat)
|
public void Load(ConfigurationFileFormat configurationFileFormat, string configurationFilePath)
|
||||||
{
|
{
|
||||||
if (configurationFileFormat.Version != 1 && configurationFileFormat.Version != 0)
|
bool configurationFileUpdated = false;
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 0 || configurationFileFormat.Version > 2)
|
||||||
{
|
{
|
||||||
Common.Logging.Logger.PrintWarning(LogClass.Application, $"Unsupported configuration version {configurationFileFormat.Version}, loading default.");
|
Common.Logging.Logger.PrintWarning(LogClass.Application, $"Unsupported configuration version {configurationFileFormat.Version}, loading default.");
|
||||||
|
|
||||||
|
@ -451,6 +461,15 @@ namespace Ryujinx.Configuration
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 2)
|
||||||
|
{
|
||||||
|
Common.Logging.Logger.PrintWarning(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, needs to be updated.");
|
||||||
|
|
||||||
|
configurationFileFormat.SystemRegion = Region.USA;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
Graphics.ShadersDumpPath.Value = configurationFileFormat.GraphicsShadersDumpPath;
|
Graphics.ShadersDumpPath.Value = configurationFileFormat.GraphicsShadersDumpPath;
|
||||||
Logger.EnableDebug.Value = configurationFileFormat.LoggingEnableDebug;
|
Logger.EnableDebug.Value = configurationFileFormat.LoggingEnableDebug;
|
||||||
Logger.EnableStub.Value = configurationFileFormat.LoggingEnableStub;
|
Logger.EnableStub.Value = configurationFileFormat.LoggingEnableStub;
|
||||||
|
@ -462,6 +481,7 @@ namespace Ryujinx.Configuration
|
||||||
Logger.FilteredClasses.Value = configurationFileFormat.LoggingFilteredClasses;
|
Logger.FilteredClasses.Value = configurationFileFormat.LoggingFilteredClasses;
|
||||||
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
|
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
|
||||||
System.Language.Value = configurationFileFormat.SystemLanguage;
|
System.Language.Value = configurationFileFormat.SystemLanguage;
|
||||||
|
System.Region.Value = configurationFileFormat.SystemRegion;
|
||||||
System.EnableDockedMode.Value = configurationFileFormat.DockedMode;
|
System.EnableDockedMode.Value = configurationFileFormat.DockedMode;
|
||||||
System.EnableDockedMode.Value = configurationFileFormat.DockedMode;
|
System.EnableDockedMode.Value = configurationFileFormat.DockedMode;
|
||||||
EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration;
|
EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration;
|
||||||
|
@ -487,6 +507,13 @@ namespace Ryujinx.Configuration
|
||||||
Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard;
|
Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard;
|
||||||
Hid.KeyboardControls.Value = configurationFileFormat.KeyboardControls;
|
Hid.KeyboardControls.Value = configurationFileFormat.KeyboardControls;
|
||||||
Hid.JoystickControls.Value = configurationFileFormat.JoystickControls;
|
Hid.JoystickControls.Value = configurationFileFormat.JoystickControls;
|
||||||
|
|
||||||
|
if (configurationFileUpdated)
|
||||||
|
{
|
||||||
|
ToFileFormat().SaveConfig(configurationFilePath);
|
||||||
|
|
||||||
|
Common.Logging.Logger.PrintWarning(LogClass.Application, "Configuration file is updated!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Initialize()
|
public static void Initialize()
|
||||||
|
|
13
Ryujinx.Common/Configuration/System/Region.cs
Normal file
13
Ryujinx.Common/Configuration/System/Region.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
namespace Ryujinx.Configuration.System
|
||||||
|
{
|
||||||
|
public enum Region
|
||||||
|
{
|
||||||
|
Japan,
|
||||||
|
USA,
|
||||||
|
Europe,
|
||||||
|
Australia,
|
||||||
|
China,
|
||||||
|
Korea,
|
||||||
|
Taiwan
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,6 +54,24 @@ namespace Ryujinx.HLE.HOS.Services.Settings
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Command(4)]
|
||||||
|
// GetRegionCode() -> u32 nn::settings::RegionCode
|
||||||
|
public ResultCode GetRegionCode(ServiceCtx context)
|
||||||
|
{
|
||||||
|
// NOTE: Service mount 0x8000000000000050 savedata and read the region code here.
|
||||||
|
|
||||||
|
SystemRegion regionCode = (SystemRegion)context.Device.System.State.DesiredRegionCode;
|
||||||
|
|
||||||
|
if (regionCode < SystemRegion.Min || regionCode > SystemRegion.Max)
|
||||||
|
{
|
||||||
|
regionCode = SystemRegion.USA;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.ResponseData.Write((uint)regionCode);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
[Command(5)]
|
[Command(5)]
|
||||||
// GetAvailableLanguageCodes2() -> (u32, buffer<nn::settings::LanguageCode, 6>)
|
// GetAvailableLanguageCodes2() -> (u32, buffer<nn::settings::LanguageCode, 6>)
|
||||||
public ResultCode GetAvailableLanguageCodes2(ServiceCtx context)
|
public ResultCode GetAvailableLanguageCodes2(ServiceCtx context)
|
||||||
|
|
16
Ryujinx.HLE/HOS/SystemState/SystemRegion.cs
Normal file
16
Ryujinx.HLE/HOS/SystemState/SystemRegion.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
namespace Ryujinx.HLE.HOS.SystemState
|
||||||
|
{
|
||||||
|
public enum SystemRegion
|
||||||
|
{
|
||||||
|
Japan,
|
||||||
|
USA,
|
||||||
|
Europe,
|
||||||
|
Australia,
|
||||||
|
China,
|
||||||
|
Korea,
|
||||||
|
Taiwan,
|
||||||
|
|
||||||
|
Min = Japan,
|
||||||
|
Max = Taiwan
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,6 +37,8 @@ namespace Ryujinx.HLE.HOS.SystemState
|
||||||
|
|
||||||
internal long DesiredLanguageCode { get; private set; }
|
internal long DesiredLanguageCode { get; private set; }
|
||||||
|
|
||||||
|
internal uint DesiredRegionCode { get; private set; }
|
||||||
|
|
||||||
public TitleLanguage DesiredTitleLanguage { get; private set; }
|
public TitleLanguage DesiredTitleLanguage { get; private set; }
|
||||||
|
|
||||||
internal string ActiveAudioOutput { get; private set; }
|
internal string ActiveAudioOutput { get; private set; }
|
||||||
|
@ -79,6 +81,11 @@ namespace Ryujinx.HLE.HOS.SystemState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetRegion(SystemRegion region)
|
||||||
|
{
|
||||||
|
DesiredRegionCode = (uint)region;
|
||||||
|
}
|
||||||
|
|
||||||
public void SetAudioOutputAsTv()
|
public void SetAudioOutputAsTv()
|
||||||
{
|
{
|
||||||
ActiveAudioOutput = AudioOutputs[0];
|
ActiveAudioOutput = AudioOutputs[0];
|
||||||
|
|
|
@ -69,6 +69,8 @@ namespace Ryujinx.HLE
|
||||||
{
|
{
|
||||||
System.State.SetLanguage((SystemLanguage)ConfigurationState.Instance.System.Language.Value);
|
System.State.SetLanguage((SystemLanguage)ConfigurationState.Instance.System.Language.Value);
|
||||||
|
|
||||||
|
System.State.SetRegion((SystemRegion)ConfigurationState.Instance.System.Region.Value);
|
||||||
|
|
||||||
EnableDeviceVsync = ConfigurationState.Instance.Graphics.EnableVsync;
|
EnableDeviceVsync = ConfigurationState.Instance.Graphics.EnableVsync;
|
||||||
|
|
||||||
// TODO: Make this reloadable and implement Docking/Undocking logic.
|
// TODO: Make this reloadable and implement Docking/Undocking logic.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": 1,
|
"version": 2,
|
||||||
"graphics_shaders_dump_path": "",
|
"graphics_shaders_dump_path": "",
|
||||||
"logging_enable_debug": false,
|
"logging_enable_debug": false,
|
||||||
"logging_enable_stub": true,
|
"logging_enable_stub": true,
|
||||||
|
@ -11,6 +11,7 @@
|
||||||
"logging_filtered_classes": [],
|
"logging_filtered_classes": [],
|
||||||
"enable_file_log": true,
|
"enable_file_log": true,
|
||||||
"system_language": "AmericanEnglish",
|
"system_language": "AmericanEnglish",
|
||||||
|
"system_region": "USA",
|
||||||
"docked_mode": false,
|
"docked_mode": false,
|
||||||
"enable_discord_integration": true,
|
"enable_discord_integration": true,
|
||||||
"enable_vsync": true,
|
"enable_vsync": true,
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace Ryujinx
|
||||||
|
|
||||||
ConfigurationFileFormat configurationFileFormat = ConfigurationFileFormat.Load(localConfigurationPath);
|
ConfigurationFileFormat configurationFileFormat = ConfigurationFileFormat.Load(localConfigurationPath);
|
||||||
|
|
||||||
ConfigurationState.Instance.Load(configurationFileFormat);
|
ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath);
|
||||||
}
|
}
|
||||||
else if (File.Exists(globalConfigurationPath))
|
else if (File.Exists(globalConfigurationPath))
|
||||||
{
|
{
|
||||||
|
@ -61,7 +61,7 @@ namespace Ryujinx
|
||||||
|
|
||||||
ConfigurationFileFormat configurationFileFormat = ConfigurationFileFormat.Load(globalConfigurationPath);
|
ConfigurationFileFormat configurationFileFormat = ConfigurationFileFormat.Load(globalConfigurationPath);
|
||||||
|
|
||||||
ConfigurationState.Instance.Load(configurationFileFormat);
|
ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace Ryujinx.Ui
|
||||||
[GUI] CheckButton _ignoreToggle;
|
[GUI] CheckButton _ignoreToggle;
|
||||||
[GUI] CheckButton _directKeyboardAccess;
|
[GUI] CheckButton _directKeyboardAccess;
|
||||||
[GUI] ComboBoxText _systemLanguageSelect;
|
[GUI] ComboBoxText _systemLanguageSelect;
|
||||||
|
[GUI] ComboBoxText _systemRegionSelect;
|
||||||
[GUI] CheckButton _custThemeToggle;
|
[GUI] CheckButton _custThemeToggle;
|
||||||
[GUI] Entry _custThemePath;
|
[GUI] Entry _custThemePath;
|
||||||
[GUI] ToggleButton _browseThemePath;
|
[GUI] ToggleButton _browseThemePath;
|
||||||
|
@ -197,6 +198,7 @@ namespace Ryujinx.Ui
|
||||||
}
|
}
|
||||||
|
|
||||||
_systemLanguageSelect.SetActiveId(ConfigurationState.Instance.System.Language.Value.ToString());
|
_systemLanguageSelect.SetActiveId(ConfigurationState.Instance.System.Language.Value.ToString());
|
||||||
|
_systemRegionSelect .SetActiveId(ConfigurationState.Instance.System.Region.Value.ToString());
|
||||||
_controller1Type .SetActiveId(ConfigurationState.Instance.Hid.ControllerType.Value.ToString());
|
_controller1Type .SetActiveId(ConfigurationState.Instance.Hid.ControllerType.Value.ToString());
|
||||||
Controller_Changed(null, null, _controller1Type.ActiveId, _controller1Image);
|
Controller_Changed(null, null, _controller1Type.ActiveId, _controller1Image);
|
||||||
|
|
||||||
|
@ -232,6 +234,7 @@ namespace Ryujinx.Ui
|
||||||
_gameDirsBox.AppendColumn("", new CellRendererText(), "text", 0);
|
_gameDirsBox.AppendColumn("", new CellRendererText(), "text", 0);
|
||||||
_gameDirsBoxStore = new ListStore(typeof(string));
|
_gameDirsBoxStore = new ListStore(typeof(string));
|
||||||
_gameDirsBox.Model = _gameDirsBoxStore;
|
_gameDirsBox.Model = _gameDirsBoxStore;
|
||||||
|
|
||||||
foreach (string gameDir in ConfigurationState.Instance.Ui.GameDirs.Value)
|
foreach (string gameDir in ConfigurationState.Instance.Ui.GameDirs.Value)
|
||||||
{
|
{
|
||||||
_gameDirsBoxStore.AppendValues(gameDir);
|
_gameDirsBoxStore.AppendValues(gameDir);
|
||||||
|
@ -438,6 +441,7 @@ namespace Ryujinx.Ui
|
||||||
};
|
};
|
||||||
|
|
||||||
ConfigurationState.Instance.System.Language.Value = (Language)Enum.Parse(typeof(Language), _systemLanguageSelect.ActiveId);
|
ConfigurationState.Instance.System.Language.Value = (Language)Enum.Parse(typeof(Language), _systemLanguageSelect.ActiveId);
|
||||||
|
ConfigurationState.Instance.System.Region.Value = (Configuration.System.Region)Enum.Parse(typeof(Configuration.System.Region), _systemRegionSelect.ActiveId);
|
||||||
ConfigurationState.Instance.Hid.ControllerType.Value = (ControllerType)Enum.Parse(typeof(ControllerType), _controller1Type.ActiveId);
|
ConfigurationState.Instance.Hid.ControllerType.Value = (ControllerType)Enum.Parse(typeof(ControllerType), _controller1Type.ActiveId);
|
||||||
ConfigurationState.Instance.Ui.CustomThemePath.Value = _custThemePath.Buffer.Text;
|
ConfigurationState.Instance.Ui.CustomThemePath.Value = _custThemePath.Buffer.Text;
|
||||||
ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = _graphicsShadersDumpPath.Buffer.Text;
|
ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = _graphicsShadersDumpPath.Buffer.Text;
|
||||||
|
|
|
@ -166,6 +166,43 @@
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Change System Region</property>
|
||||||
|
<property name="halign">end</property>
|
||||||
|
<property name="label" translatable="yes">System Region:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
<property name="padding">5</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBoxText" id="_systemRegionSelect">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Change System Region</property>
|
||||||
|
<property name="margin_left">5</property>
|
||||||
|
<items>
|
||||||
|
<item id="Japan" translatable="yes">Japan</item>
|
||||||
|
<item id="USA" translatable="yes">USA</item>
|
||||||
|
<item id="Europe" translatable="yes">Europe</item>
|
||||||
|
<item id="Australia" translatable="yes">Australia</item>
|
||||||
|
<item id="China" translatable="yes">China</item>
|
||||||
|
<item id="Korea" translatable="yes">Korea</item>
|
||||||
|
<item id="Taiwan" translatable="yes">Taiwan</item>
|
||||||
|
</items>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
"logging_filtered_classes",
|
"logging_filtered_classes",
|
||||||
"enable_file_log",
|
"enable_file_log",
|
||||||
"system_language",
|
"system_language",
|
||||||
|
"system_region",
|
||||||
"docked_mode",
|
"docked_mode",
|
||||||
"enable_vsync",
|
"enable_vsync",
|
||||||
"enable_multicore_scheduling",
|
"enable_multicore_scheduling",
|
||||||
|
@ -402,6 +403,25 @@
|
||||||
"AmericanEnglish"
|
"AmericanEnglish"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"system_region": {
|
||||||
|
"$id": "#/properties/system_region",
|
||||||
|
"type": "string",
|
||||||
|
"title": "System Region",
|
||||||
|
"description": "Change System Region",
|
||||||
|
"default": "USA",
|
||||||
|
"enum": [
|
||||||
|
"Japan",
|
||||||
|
"USA",
|
||||||
|
"Europe",
|
||||||
|
"Australia",
|
||||||
|
"China",
|
||||||
|
"Korea",
|
||||||
|
"Taiwan"
|
||||||
|
],
|
||||||
|
"examples": [
|
||||||
|
"USA"
|
||||||
|
]
|
||||||
|
},
|
||||||
"docked_mode": {
|
"docked_mode": {
|
||||||
"$id": "#/properties/docked_mode",
|
"$id": "#/properties/docked_mode",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|
Reference in a new issue