Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a789ba4
add changes to make compilable for hk 1.5.12301
SFGrenade Dec 16, 2025
ad0ffab
it wasn't public, it was private
SFGrenade Dec 16, 2025
bad9b70
do fancy private stuff
SFGrenade Dec 16, 2025
dcfaa9f
language doesn't need to get patched if it doesn't exist in the first…
SFGrenade Dec 17, 2025
e4e10bc
use `MonoMod.MonoModLinkFrom`
SFGrenade Dec 18, 2025
7a06e12
adjust patches to methods how they appear in dnspy v6.2.0
SFGrenade Dec 23, 2025
e0e6d67
make use of game's vanilla binaries & don't have newtonsoft and mscor…
SFGrenade Dec 23, 2025
e91596f
remove unused method
SFGrenade Dec 31, 2025
bff85a4
remove base onenter
SFGrenade Dec 31, 2025
7b64c07
made loading work better
SFGrenade Dec 31, 2025
9adc878
update hollowknight.version
SFGrenade Feb 11, 2026
86d0b1b
full canvas, no offsets & modloader obj
SFGrenade Feb 11, 2026
c835383
Merge branch 'master' into hk-beta-branch-unity-6-update
SFGrenade Feb 11, 2026
05b3ccf
add one backwards-compatability property
SFGrenade Feb 18, 2026
207132d
who needs reflection if you have monomod fuckery
SFGrenade Feb 18, 2026
9674f71
accidental double newline
SFGrenade Feb 18, 2026
b74e35b
make comment clear
SFGrenade Feb 18, 2026
7211d50
don't relink the entirety of TCLL, just the `get(str, str)` method
SFGrenade Feb 28, 2026
2252e7d
MonoModLinkFrom has only 1 arg
SFGrenade Feb 28, 2026
32ab611
not just desktopplatform with `EncryptedSharedData`
SFGrenade Feb 28, 2026
ae7998b
make it an obsolete warning
SFGrenade Feb 28, 2026
fc2be8c
try to have type forwarding
SFGrenade Feb 28, 2026
a63c33e
add postpatcher
SFGrenade Feb 28, 2026
f1703aa
more methods for language
SFGrenade Feb 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
## files generated by popular Visual Studio add-ons.

PrePatcher/Output
PostPatcher/Output

# User-specific files
*.suo
Expand Down
120 changes: 42 additions & 78 deletions Assembly-CSharp/Assembly-CSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<RestorePackagesPath>packages</RestorePackagesPath>
<LangVersion>latest</LangVersion>
<DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
</PropertyGroup>

<ItemGroup>
<Files Include="../Vanilla/*" />

<BuildDir Include="$(TargetDir)" />

<Dependencies Include="$(TargetDir)Newtonsoft.Json.dll" />

<Dependencies Include="$(TargetDir)MMHOOK_Assembly-CSharp.dll" />
<Dependencies Include="$(TargetDir)MMHOOK_PlayMaker.dll" />
<Dependencies Include="$(TargetDir)MonoMod.Utils.dll" />
Expand All @@ -30,8 +30,8 @@
<!-- todo macOS -->
<GamePath Condition="'$(OS)' == 'Windows_NT'">C:/Program Files (x86)/Steam/steamapps/common/Hollow Knight</GamePath>
<GamePath Condition="'$(OS)' != 'Windows_NT'">$(HOME)/.local/share/Steam/steamapps/common/Hollow Knight</GamePath>
<CopyDir>$(GamePath)/hollow_knight_Data/Managed</CopyDir>
<CopyDir>$(GamePath)/hollow_knight_Data/Managed</CopyDir>

<Mono Condition="$(OS) == WINDOWS_NT" />
<Mono Condition="$(OS) != WINDOWS_NT">mono</Mono>
</PropertyGroup>
Expand All @@ -41,12 +41,23 @@

<Copy SkipUnchangedFiles="true" SourceFiles="@(Files)" DestinationFolder="@(BuildDir)" />

<Copy SourceFiles="$(TargetDir)Assembly-CSharp.dll" DestinationFiles="$(TargetDir)steps-1.Assembly-CSharp.dll" />

<Exec WorkingDirectory="@(BuildDir)" Command="$(Mono) &quot;$(MSBuildProjectDirectory)/../PrePatcher/Output/PrePatcher.exe&quot; Assembly-CSharp.dll Assembly-CSharp-patched.dll" />
<Copy SkipUnchangedFiles="true" SourceFiles="$(TargetDir)Assembly-CSharp-patched.dll" DestinationFiles="$(TargetDir)Assembly-CSharp.dll" />

<Copy SourceFiles="$(TargetDir)Assembly-CSharp.dll" DestinationFiles="$(TargetDir)steps-2.Assembly-CSharp.dll" />

<Delete Condition="Exists('MONOMODDED_Assembly-CSharp.dll')" Files="MONOMODDED_Assembly-CSharp.dll" />
<Exec WorkingDirectory="@(BuildDir)" Command="$(Mono) MonoMod.exe Assembly-CSharp.dll" />

<Copy SourceFiles="$(TargetDir)MONOMODDED_Assembly-CSharp.dll" DestinationFiles="$(TargetDir)steps-3.MONOMODDED_Assembly-CSharp.dll" />

<Exec WorkingDirectory="@(BuildDir)" Command="$(Mono) &quot;$(MSBuildProjectDirectory)/../PostPatcher/Output/PostPatcher.exe&quot; MONOMODDED_Assembly-CSharp.dll Assembly-CSharp-postpatched.dll" />
<Copy SkipUnchangedFiles="true" SourceFiles="$(TargetDir)Assembly-CSharp-postpatched.dll" DestinationFiles="$(TargetDir)MONOMODDED_Assembly-CSharp.dll" />

<Copy SourceFiles="$(TargetDir)MONOMODDED_Assembly-CSharp.dll" DestinationFiles="$(TargetDir)steps-4.MONOMODDED_Assembly-CSharp.dll" />

<!-- Generate Hooks !-->
<Exec Condition="!Exists('$(TargetDir)MMHOOK_Assembly-CSharp.dll')" WorkingDirectory="@(BuildDir)" Command="$(Mono) MonoMod.RuntimeDetour.HookGen.exe --private Assembly-CSharp.dll" />
<Exec Condition="!Exists('$(TargetDir)MMHOOK_Playmaker.dll')" WorkingDirectory="@(BuildDir)" Command="$(Mono) MonoMod.RuntimeDetour.HookGen.exe --private PlayMaker.dll" />
Expand All @@ -58,30 +69,28 @@
<!-- Copy the vanilla files. -->
<Copy SourceFiles="@(Files)" DestinationFolder="../Examples/HollowKnightManaged/" />
<!-- Copy the API and the documentation -->
<Copy SourceFiles="$(TargetDir)MONOMODDED_Assembly-CSharp.dll" DestinationFiles="../Examples/HollowKnightManaged/Assembly-CSharp.dll" />
<Copy SourceFiles="$(TargetDir)Assembly-CSharp-postpatched.dll" DestinationFiles="../Examples/HollowKnightManaged/Assembly-CSharp.dll" />
<Copy SourceFiles="$(TargetDir)Assembly-CSharp.mm.xml" DestinationFiles="../Examples/HollowKnightManaged/Assembly-CSharp.xml" />

<!-- Copy the dependencies for the API and hooks for mods -->
<Copy SourceFiles="@(Dependencies)" DestinationFolder="../Examples/HollowKnightManaged/" />
</Target>

<Target Name="OutputFinal" AfterTargets="PostBuild">
<!-- Cleanup -->
<RemoveDir Directories="$(OutputDir)/" />

<!-- Make the output directory -->
<MakeDir Directories="$(OutputDir)/" />

<!-- Copy the API, the documentation, the overridden mscorlib, and the README. -->
<!-- Copy the API, the documentation, and the README. -->
<Copy SourceFiles="../README.ModdingApi.md" DestinationFiles="$(OutputDir)/README.md" />
<Copy SourceFiles="../override/mscorlib.dll" DestinationFiles="$(OutputDir)/mscorlib.dll" />
<Copy SourceFiles="../override/mscorlib.xml" DestinationFiles="$(OutputDir)/mscorlib.xml" />
<Copy SourceFiles="$(TargetDir)MONOMODDED_Assembly-CSharp.dll" DestinationFiles="$(OutputDir)/Assembly-CSharp.dll" />
<Copy SourceFiles="$(TargetDir)Assembly-CSharp-postpatched.dll" DestinationFiles="$(OutputDir)/Assembly-CSharp.dll" />
<Copy SourceFiles="$(TargetDir)Assembly-CSharp.mm.xml" DestinationFiles="$(OutputDir)/Assembly-CSharp.xml" />

<!-- Copy the dependencies for the API and hooks for mods -->
<Copy SourceFiles="@(Dependencies)" DestinationFolder="$(OutputDir)" />

<PropertyGroup>
<NativeLibPrefix Condition="'$(RuntimeIdentifier)' == 'win-x64'" />
<NativeLibExtension Condition="'$(RuntimeIdentifier)' == 'win-x64'">.dll</NativeLibExtension>
Expand All @@ -95,14 +104,14 @@
<!-- on .NET 5 and up, msbuild can automatically copy the relevant files from /runtimes/$RID/native/library.{dll,so,dylib}. Unfortunately, we're on net472 -->
<Copy Condition="'$(RuntimeIdentifier)' != ''" SourceFiles="$(Pkgunityscenerepacker)/runtimes/$(RuntimeIdentifier)/native/$(NativeLibPrefix)unityscenerepacker$(NativeLibExtension)" DestinationFolder="$(OutputDir)" />
</Target>

<Target Name="CopyOutputAfterFinal" AfterTargets="OutputFinal" Condition="'$(CopyDir)' != ''">
<ItemGroup>
<OutputFiles Include="$(OutputDir)\**\*" />
</ItemGroup>
<Copy SourceFiles="@(OutputFiles)" DestinationFolder="$(CopyDir)" />
</Target>

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
<DocumentationFile>bin\$(Configuration)\Assembly-CSharp.mm.xml</DocumentationFile>
Expand All @@ -120,85 +129,40 @@
<PackageReference Include="MonoMod.RuntimeDetour" Version="21.4.29.1">
<IncludeAssets>all</IncludeAssets>
</PackageReference>

<PackageReference Include="MonoMod.RuntimeDetour.HookGen" Version="21.4.29.1">
<IncludeAssets>all</IncludeAssets>
</PackageReference>

<PackageReference Include="unityscenerepacker" Version="2.4.0" GeneratePathProperty="true" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="../PrePatcher/PrePatcher.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="../PostPatcher/PostPatcher.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="logo.png"/>
<!-- generated using https://github.com/jakobhellermann/unity-scene-repacker/blob/main/examples/export_monobehaviour_typetrees.rs -->
<EmbeddedResource Include="monobehaviour-typetree-dump.lz4" />
</ItemGroup>

<ItemGroup>
<Reference Include="Assembly-CSharp, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>../Vanilla/Assembly-CSharp.dll</HintPath>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<HintPath>..\override\mscorlib.dll</HintPath>
</Reference>
<Reference Include="netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
<HintPath>../Vanilla/netstandard.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../JsonNet/Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="PlayMaker, Version=1.6.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>../Vanilla/PlayMaker.dll</HintPath>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../Vanilla/UnityEngine.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AnimationModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../Vanilla/UnityEngine.AnimationModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AssetBundleModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../Vanilla/UnityEngine.AssetBundleModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AudioModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../Vanilla/UnityEngine.AudioModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../Vanilla/UnityEngine.CoreModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ImageConversionModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../Vanilla/UnityEngine.ImageConversionModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.IMGUIModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../Vanilla/UnityEngine.IMGUIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.InputLegacyModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../Vanilla/UnityEngine.InputLegacyModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.JSONSerializeModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../Vanilla/UnityEngine.JSONSerializeModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ParticleSystemModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../Vanilla/UnityEngine.ParticleSystemModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.Physics2DModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../Vanilla/UnityEngine.Physics2DModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TextRenderingModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../Vanilla/UnityEngine.TextRenderingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../Vanilla/UnityEngine.UI.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UIModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>../Vanilla/UnityEngine.UIModule.dll</HintPath>
</Reference>
<Reference Include="../Vanilla/Assembly-CSharp.dll"/>
<Reference Include="../Vanilla/mscorlib.dll"/>
<!--<Reference Include="../override/mscorlib.dll"/>-->
<Reference Include="../Vanilla/netstandard.dll"/>
<Reference Include="../Vanilla/Newtonsoft.Json.dll"/>
<Reference Include="../Vanilla/PlayMaker.dll"/>
<Reference Include="../Vanilla/UnityEngine.dll"/>
<Reference Include="../Vanilla/UnityEngine.*.dll"/>
<Reference Include="../Vanilla/TeamCherry.*.dll"/>
<Reference Include="../Vanilla/System.dll"/>
<Reference Include="../Vanilla/System.*.dll"/>
</ItemGroup>
</Project>
3 changes: 2 additions & 1 deletion Assembly-CSharp/Console.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ public void Start()
string.Join(string.Empty, _messages.ToArray()),
_fontSize,
TextAnchor.LowerLeft,
new CanvasUtil.RectData(new Vector2(-5, -5), Vector2.zero, Vector2.zero, Vector2.one),
//new CanvasUtil.RectData(new Vector2(-5, -5), Vector2.zero, Vector2.zero, Vector2.one),
new CanvasUtil.RectData(Vector2.zero, Vector2.zero, Vector2.zero, Vector2.one),
_font
);

Expand Down
91 changes: 91 additions & 0 deletions Assembly-CSharp/Language/Language.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using UObject = UnityEngine.Object;
using USystemLanguage = UnityEngine.SystemLanguage;

namespace Language;

[Obsolete("Use `TeamCherry.Localization.Language` instead.")]
public static class Language
{
public static void LoadLanguage() => COMPAT_LoadLanguage();
public static void LoadAvailableLanguages() => COMPAT_LoadAvailableLanguages();
public static string[] GetLanguages() => COMPAT_GetLanguages();
public static bool SwitchLanguage(string langCode) => COMPAT_SwitchLanguage(langCode);
public static bool SwitchLanguage(LanguageCode code) => COMPAT_SwitchLanguage((TeamCherry.Localization.LanguageCode) code);
public static UObject GetAsset(string name) => COMPAT_GetAsset(name);
public static LanguageCode CurrentLanguage() => (LanguageCode) COMPAT_CurrentLanguage();
public static string Get(string key) => COMPAT_Get(key);
public static IEnumerable<string> GetSheets() => COMPAT_GetSheets();
public static IEnumerable<string> GetKeys(string sheetTitle) => COMPAT_GetKeys(sheetTitle);
public static bool Has(string key) => COMPAT_Has(key);
public static bool Has(string key, string sheet) => COMPAT_Has(key, sheet);
public static bool HasSheet(string sheet) => COMPAT_HasSheet(sheet);
public static LanguageCode LanguageNameToCode(USystemLanguage name) => (LanguageCode) COMPAT_LanguageNameToCode(name);
public static string GetInternal(string key, string sheetTitle) => COMPAT_Get(key, sheetTitle);
[MonoMod.MonoModLinkFrom("System.String TeamCherry.Localization.Language::Get(System.String,System.String)")]
public static string Get(string key, string sheetTitle) => Modding.ModHooks.LanguageGet(key, sheetTitle);

private static void DoSwitch(LanguageCode newLang) => COMPAT_DoSwitch((TeamCherry.Localization.LanguageCode) newLang);
private static bool HasLanguageFile(string lang, string sheetTitle) => COMPAT_HasLanguageFile(lang, sheetTitle);
private static string GetLanguageFileContents(string sheetTitle) => COMPAT_GetLanguageFileContents(sheetTitle);

// Keep these below the `[MonoMod.MonoModLinkFrom("TeamCherry.Localization.Language")]`, as the reverse order would cause a cyclic loop of methods calling themselves
// thanks to MonoMod resolving these links top-down
// which would make a `LinkTo(TCLL)->LinkFrom(TCLL)` into a fully recursive function ⟳
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Void LoadLanguage()")]
[MonoMod.MonoModRemove]
private static extern void COMPAT_LoadLanguage();
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Void LoadAvailableLanguages()")]
[MonoMod.MonoModRemove]
private static extern void COMPAT_LoadAvailableLanguages();
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.String[] GetLanguages()")]
[MonoMod.MonoModRemove]
private static extern string[] COMPAT_GetLanguages();
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Boolean SwitchLanguage(System.String)")]
[MonoMod.MonoModRemove]
private static extern bool COMPAT_SwitchLanguage(string langCode);
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Boolean SwitchLanguage(TeamCherry.Localization.LanguageCode)")]
[MonoMod.MonoModRemove]
private static extern bool COMPAT_SwitchLanguage(TeamCherry.Localization.LanguageCode code);
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "UnityEngine.Object GetAsset(System.String)")]
[MonoMod.MonoModRemove]
private static extern UObject COMPAT_GetAsset(string name);
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "TeamCherry.Localization.LanguageCode CurrentLanguage()")]
[MonoMod.MonoModRemove]
private static extern TeamCherry.Localization.LanguageCode COMPAT_CurrentLanguage();
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.String Get(System.String)")]
[MonoMod.MonoModRemove]
private static extern string COMPAT_Get(string key);
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.String Get(System.String,System.String)")]
[MonoMod.MonoModRemove]
private static extern string COMPAT_Get(string key, string sheetTitle);
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Collections.Generic.IEnumerable`1<System.String> GetSheets()")]
[MonoMod.MonoModRemove]
private static extern IEnumerable<string> COMPAT_GetSheets();
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Collections.Generic.IEnumerable`1<System.String> GetKeys(System.String)")]
[MonoMod.MonoModRemove]
private static extern IEnumerable<string> COMPAT_GetKeys(string sheetTitle);
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Boolean Has(System.String)")]
[MonoMod.MonoModRemove]
private static extern bool COMPAT_Has(string key);
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Boolean Has(System.String,System.String)")]
[MonoMod.MonoModRemove]
private static extern bool COMPAT_Has(string key, string sheet);
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Boolean HasSheet(System.String)")]
[MonoMod.MonoModRemove]
private static extern bool COMPAT_HasSheet(string sheet);
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "TeamCherry.Localization.LanguageCode LanguageNameToCode(UnityEngine.SystemLanguage)")]
[MonoMod.MonoModRemove]
private static extern TeamCherry.Localization.LanguageCode COMPAT_LanguageNameToCode(USystemLanguage name);
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Void DoSwitch(TeamCherry.Localization.LanguageCode)")]
[MonoMod.MonoModRemove]
private static extern TeamCherry.Localization.LanguageCode COMPAT_DoSwitch(TeamCherry.Localization.LanguageCode name);
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Boolean HasLanguageFile(System.String,System.String)")]
[MonoMod.MonoModRemove]
private static extern bool COMPAT_HasLanguageFile(string lang, string sheetTitle);
[MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.String GetLanguageFileContents(System.String)")]
[MonoMod.MonoModRemove]
private static extern string COMPAT_GetLanguageFileContents(string sheetTitle);
}
Loading
Loading