mirror of
https://github.com/JustArchiNET/ArchiSteamFarm
synced 2024-11-10 07:04:27 +00:00
Cleanup round
This commit is contained in:
parent
b6772b9b1e
commit
ef52e076d3
12 changed files with 70 additions and 67 deletions
|
@ -19,6 +19,13 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#if NETFRAMEWORK
|
||||
using ArchiSteamFarm.RuntimeCompatibility;
|
||||
using File = System.IO.File;
|
||||
using Path = System.IO.Path;
|
||||
#else
|
||||
using System.IO;
|
||||
#endif
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
@ -30,14 +37,6 @@ using ArchiSteamFarm.Localization;
|
|||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
|
||||
#if NETFRAMEWORK
|
||||
using ArchiSteamFarm.RuntimeCompatibility;
|
||||
using File = System.IO.File;
|
||||
using Path = System.IO.Path;
|
||||
#else
|
||||
using System.IO;
|
||||
#endif
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper {
|
||||
internal sealed class GlobalCache : SerializableFile {
|
||||
private static string SharedFilePath => Path.Combine(ArchiSteamFarm.SharedInfo.ConfigDirectory, nameof(SteamTokenDumper) + ".cache");
|
||||
|
|
|
@ -43,8 +43,6 @@ using ArchiSteamFarm.Web;
|
|||
using JetBrains.Annotations;
|
||||
using SteamKit2;
|
||||
using SteamKit2.Discovery;
|
||||
using File = ArchiSteamFarm.RuntimeCompatibility.File;
|
||||
using Path = ArchiSteamFarm.RuntimeCompatibility.Path;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
public static class ASF {
|
||||
|
@ -94,8 +92,8 @@ namespace ArchiSteamFarm {
|
|||
}
|
||||
|
||||
return fileType switch {
|
||||
EFileType.Config => System.IO.Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalConfigFileName),
|
||||
EFileType.Database => System.IO.Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalDatabaseFileName),
|
||||
EFileType.Config => Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalConfigFileName),
|
||||
EFileType.Database => Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalDatabaseFileName),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(fileType))
|
||||
};
|
||||
}
|
||||
|
@ -236,7 +234,7 @@ namespace ArchiSteamFarm {
|
|||
|
||||
try {
|
||||
// If backup directory from previous update exists, it's a good idea to purge it now
|
||||
string backupDirectory = System.IO.Path.Combine(SharedInfo.HomeDirectory, SharedInfo.UpdateDirectory);
|
||||
string backupDirectory = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.UpdateDirectory);
|
||||
|
||||
if (Directory.Exists(backupDirectory)) {
|
||||
ArchiLogger.LogGenericInfo(Strings.UpdateCleanup);
|
||||
|
@ -364,9 +362,9 @@ namespace ArchiSteamFarm {
|
|||
}
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
|
||||
string executable = System.IO.Path.Combine(SharedInfo.HomeDirectory, SharedInfo.AssemblyName);
|
||||
string executable = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.AssemblyName);
|
||||
|
||||
if (System.IO.File.Exists(executable)) {
|
||||
if (File.Exists(executable)) {
|
||||
OS.UnixSetFileAccess(executable, OS.EUnixPermission.Combined755);
|
||||
}
|
||||
}
|
||||
|
@ -508,7 +506,7 @@ namespace ArchiSteamFarm {
|
|||
throw new ArgumentNullException(nameof(fullPath));
|
||||
}
|
||||
|
||||
string extension = System.IO.Path.GetExtension(name);
|
||||
string extension = Path.GetExtension(name);
|
||||
|
||||
switch (extension) {
|
||||
case SharedInfo.JsonConfigExtension:
|
||||
|
@ -564,7 +562,7 @@ namespace ArchiSteamFarm {
|
|||
throw new ArgumentNullException(nameof(fullPath));
|
||||
}
|
||||
|
||||
string extension = System.IO.Path.GetExtension(name);
|
||||
string extension = Path.GetExtension(name);
|
||||
|
||||
switch (extension) {
|
||||
case SharedInfo.IPCConfigExtension:
|
||||
|
@ -587,7 +585,7 @@ namespace ArchiSteamFarm {
|
|||
throw new ArgumentNullException(nameof(fullPath));
|
||||
}
|
||||
|
||||
string extension = System.IO.Path.GetExtension(name);
|
||||
string extension = Path.GetExtension(name);
|
||||
|
||||
switch (extension) {
|
||||
case SharedInfo.JsonConfigExtension:
|
||||
|
@ -615,7 +613,7 @@ namespace ArchiSteamFarm {
|
|||
throw new InvalidOperationException(nameof(Bot.Bots));
|
||||
}
|
||||
|
||||
string botName = System.IO.Path.GetFileNameWithoutExtension(name);
|
||||
string botName = Path.GetFileNameWithoutExtension(name);
|
||||
|
||||
if (string.IsNullOrEmpty(botName) || (botName[0] == '.')) {
|
||||
return;
|
||||
|
@ -660,7 +658,7 @@ namespace ArchiSteamFarm {
|
|||
throw new InvalidOperationException(nameof(Bot.Bots));
|
||||
}
|
||||
|
||||
string botName = System.IO.Path.GetFileNameWithoutExtension(name);
|
||||
string botName = Path.GetFileNameWithoutExtension(name);
|
||||
|
||||
if (string.IsNullOrEmpty(botName) || (botName[0] == '.')) {
|
||||
return;
|
||||
|
@ -706,7 +704,7 @@ namespace ArchiSteamFarm {
|
|||
throw new ArgumentNullException(nameof(fullPath));
|
||||
}
|
||||
|
||||
string extension = System.IO.Path.GetExtension(name);
|
||||
string extension = Path.GetExtension(name);
|
||||
|
||||
switch (extension) {
|
||||
case SharedInfo.IPCConfigExtension:
|
||||
|
@ -729,7 +727,7 @@ namespace ArchiSteamFarm {
|
|||
throw new ArgumentNullException(nameof(fullPath));
|
||||
}
|
||||
|
||||
string extension = System.IO.Path.GetExtension(name);
|
||||
string extension = Path.GetExtension(name);
|
||||
|
||||
switch (extension) {
|
||||
case SharedInfo.JsonConfigExtension:
|
||||
|
@ -753,7 +751,7 @@ namespace ArchiSteamFarm {
|
|||
throw new InvalidOperationException(nameof(Bot.Bots));
|
||||
}
|
||||
|
||||
string botName = System.IO.Path.GetFileNameWithoutExtension(name);
|
||||
string botName = Path.GetFileNameWithoutExtension(name);
|
||||
|
||||
if (string.IsNullOrEmpty(botName)) {
|
||||
return;
|
||||
|
@ -764,7 +762,7 @@ namespace ArchiSteamFarm {
|
|||
}
|
||||
|
||||
if (botName.Equals(SharedInfo.ASF, StringComparison.OrdinalIgnoreCase)) {
|
||||
if (System.IO.File.Exists(fullPath)) {
|
||||
if (File.Exists(fullPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -772,7 +770,7 @@ namespace ArchiSteamFarm {
|
|||
// If that's the case, we wait for maximum of 5 seconds before shutting down
|
||||
await Task.Delay(5000).ConfigureAwait(false);
|
||||
|
||||
if (System.IO.File.Exists(fullPath)) {
|
||||
if (File.Exists(fullPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -857,7 +855,7 @@ namespace ArchiSteamFarm {
|
|||
HashSet<string> botNames;
|
||||
|
||||
try {
|
||||
botNames = Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*" + SharedInfo.JsonConfigExtension).Select(System.IO.Path.GetFileNameWithoutExtension).Where(botName => !string.IsNullOrEmpty(botName) && IsValidBotName(botName)).ToHashSet(Bot.BotsComparer)!;
|
||||
botNames = Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*" + SharedInfo.JsonConfigExtension).Select(Path.GetFileNameWithoutExtension).Where(botName => !string.IsNullOrEmpty(botName) && IsValidBotName(botName)).ToHashSet(Bot.BotsComparer)!;
|
||||
} catch (Exception e) {
|
||||
ArchiLogger.LogGenericException(e);
|
||||
|
||||
|
@ -926,10 +924,10 @@ namespace ArchiSteamFarm {
|
|||
}
|
||||
|
||||
// Firstly we'll move all our existing files to a backup directory
|
||||
string backupDirectory = System.IO.Path.Combine(targetDirectory, SharedInfo.UpdateDirectory);
|
||||
string backupDirectory = Path.Combine(targetDirectory, SharedInfo.UpdateDirectory);
|
||||
|
||||
foreach (string file in Directory.EnumerateFiles(targetDirectory, "*", SearchOption.AllDirectories)) {
|
||||
string fileName = System.IO.Path.GetFileName(file);
|
||||
string fileName = Path.GetFileName(file);
|
||||
|
||||
if (string.IsNullOrEmpty(fileName)) {
|
||||
ArchiLogger.LogNullError(nameof(fileName));
|
||||
|
@ -937,7 +935,7 @@ namespace ArchiSteamFarm {
|
|||
return false;
|
||||
}
|
||||
|
||||
string relativeFilePath = Path.GetRelativePath(targetDirectory, file);
|
||||
string relativeFilePath = RuntimeCompatibility.Path.GetRelativePath(targetDirectory, file);
|
||||
|
||||
if (string.IsNullOrEmpty(relativeFilePath)) {
|
||||
ArchiLogger.LogNullError(nameof(relativeFilePath));
|
||||
|
@ -945,7 +943,7 @@ namespace ArchiSteamFarm {
|
|||
return false;
|
||||
}
|
||||
|
||||
string? relativeDirectoryName = System.IO.Path.GetDirectoryName(relativeFilePath);
|
||||
string? relativeDirectoryName = Path.GetDirectoryName(relativeFilePath);
|
||||
|
||||
switch (relativeDirectoryName) {
|
||||
case null:
|
||||
|
@ -978,11 +976,11 @@ namespace ArchiSteamFarm {
|
|||
break;
|
||||
}
|
||||
|
||||
string targetBackupDirectory = relativeDirectoryName.Length > 0 ? System.IO.Path.Combine(backupDirectory, relativeDirectoryName) : backupDirectory;
|
||||
string targetBackupDirectory = relativeDirectoryName.Length > 0 ? Path.Combine(backupDirectory, relativeDirectoryName) : backupDirectory;
|
||||
Directory.CreateDirectory(targetBackupDirectory);
|
||||
|
||||
string targetBackupFile = System.IO.Path.Combine(targetBackupDirectory, fileName);
|
||||
File.Move(file, targetBackupFile, true);
|
||||
string targetBackupFile = Path.Combine(targetBackupDirectory, fileName);
|
||||
RuntimeCompatibility.File.Move(file, targetBackupFile, true);
|
||||
}
|
||||
|
||||
// We can now get rid of directories that are empty
|
||||
|
@ -994,17 +992,17 @@ namespace ArchiSteamFarm {
|
|||
|
||||
// Now enumerate over files in the zip archive, skip directory entries that we're not interested in (we can create them ourselves if needed)
|
||||
foreach (ZipArchiveEntry zipFile in archive.Entries.Where(zipFile => !string.IsNullOrEmpty(zipFile.Name))) {
|
||||
string file = System.IO.Path.Combine(targetDirectory, zipFile.FullName);
|
||||
string file = Path.Combine(targetDirectory, zipFile.FullName);
|
||||
|
||||
if (System.IO.File.Exists(file)) {
|
||||
if (File.Exists(file)) {
|
||||
// This is possible only with files that we decided to leave in place during our backup function
|
||||
string targetBackupFile = file + ".bak";
|
||||
File.Move(file, targetBackupFile, true);
|
||||
RuntimeCompatibility.File.Move(file, targetBackupFile, true);
|
||||
}
|
||||
|
||||
// Check if this file requires its own folder
|
||||
if (zipFile.Name != zipFile.FullName) {
|
||||
string? directory = System.IO.Path.GetDirectoryName(file);
|
||||
string? directory = Path.GetDirectoryName(file);
|
||||
|
||||
if (string.IsNullOrEmpty(directory)) {
|
||||
ArchiLogger.LogNullError(nameof(directory));
|
||||
|
|
|
@ -19,6 +19,13 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#if NETFRAMEWORK
|
||||
using ArchiSteamFarm.RuntimeCompatibility;
|
||||
|
||||
using File = System.IO.File;
|
||||
#else
|
||||
using System.IO;
|
||||
#endif
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
|
@ -34,14 +41,6 @@ using Newtonsoft.Json;
|
|||
using Newtonsoft.Json.Linq;
|
||||
using SteamKit2;
|
||||
|
||||
#if NETFRAMEWORK
|
||||
using ArchiSteamFarm.RuntimeCompatibility;
|
||||
|
||||
using File = System.IO.File;
|
||||
#else
|
||||
using System.IO;
|
||||
#endif
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
public sealed class BotConfig {
|
||||
|
|
|
@ -23,13 +23,13 @@ using System;
|
|||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Collections;
|
||||
using ArchiSteamFarm.Helpers;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using Newtonsoft.Json;
|
||||
using File = ArchiSteamFarm.RuntimeCompatibility.File;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal sealed class BotDatabase : SerializableFile {
|
||||
|
@ -141,14 +141,14 @@ namespace ArchiSteamFarm {
|
|||
throw new ArgumentNullException(nameof(filePath));
|
||||
}
|
||||
|
||||
if (!System.IO.File.Exists(filePath)) {
|
||||
if (!File.Exists(filePath)) {
|
||||
return new BotDatabase(filePath);
|
||||
}
|
||||
|
||||
BotDatabase? botDatabase;
|
||||
|
||||
try {
|
||||
string json = await File.ReadAllTextAsync(filePath).ConfigureAwait(false);
|
||||
string json = await RuntimeCompatibility.File.ReadAllTextAsync(filePath).ConfigureAwait(false);
|
||||
|
||||
if (string.IsNullOrEmpty(json)) {
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
|
||||
|
|
|
@ -31,11 +31,10 @@ using ArchiSteamFarm.Callbacks;
|
|||
using ArchiSteamFarm.Json;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.Plugins;
|
||||
using ArchiSteamFarm.RuntimeCompatibility;
|
||||
using JetBrains.Annotations;
|
||||
using SteamKit2;
|
||||
|
||||
using ArchiSteamFarm.RuntimeCompatibility;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
public sealed class Commands {
|
||||
private const ushort SteamTypingStatusDelay = 10 * 1000; // Steam client broadcasts typing status each 10 seconds
|
||||
|
|
|
@ -32,10 +32,12 @@ using ArchiSteamFarm.Localization;
|
|||
using ArchiSteamFarm.SteamKit2;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using File = ArchiSteamFarm.RuntimeCompatibility.File;
|
||||
|
||||
#if NETFRAMEWORK
|
||||
using ArchiSteamFarm.RuntimeCompatibility;
|
||||
using File = System.IO.File;
|
||||
#else
|
||||
using System.IO;
|
||||
#endif
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
|
@ -122,7 +124,7 @@ namespace ArchiSteamFarm {
|
|||
throw new ArgumentNullException(nameof(filePath));
|
||||
}
|
||||
|
||||
if (!System.IO.File.Exists(filePath)) {
|
||||
if (!File.Exists(filePath)) {
|
||||
GlobalDatabase result = new(filePath);
|
||||
|
||||
Utilities.InBackground(result.Save);
|
||||
|
@ -133,7 +135,7 @@ namespace ArchiSteamFarm {
|
|||
GlobalDatabase? globalDatabase;
|
||||
|
||||
try {
|
||||
string json = await File.ReadAllTextAsync(filePath).ConfigureAwait(false);
|
||||
string json = await RuntimeCompatibility.File.ReadAllTextAsync(filePath).ConfigureAwait(false);
|
||||
|
||||
if (string.IsNullOrEmpty(json)) {
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
|
||||
|
|
|
@ -19,6 +19,13 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#if NETFRAMEWORK
|
||||
using ArchiSteamFarm.RuntimeCompatibility;
|
||||
using File = System.IO.File;
|
||||
using Path = System.IO.Path;
|
||||
#else
|
||||
using Microsoft.Extensions.Hosting;
|
||||
#endif
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -32,14 +39,6 @@ using Newtonsoft.Json;
|
|||
using Newtonsoft.Json.Linq;
|
||||
using NLog.Web;
|
||||
|
||||
#if NETFRAMEWORK
|
||||
using ArchiSteamFarm.RuntimeCompatibility;
|
||||
using File = System.IO.File;
|
||||
using Path = System.IO.Path;
|
||||
#else
|
||||
using Microsoft.Extensions.Hosting;
|
||||
#endif
|
||||
|
||||
namespace ArchiSteamFarm.IPC {
|
||||
internal static class ArchiKestrel {
|
||||
internal static HistoryTarget? HistoryTarget { get; private set; }
|
||||
|
|
|
@ -42,6 +42,10 @@ using Newtonsoft.Json.Serialization;
|
|||
#if NETFRAMEWORK
|
||||
using ArchiSteamFarm.RuntimeCompatibility;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using File = System.IO.File;
|
||||
using Path = System.IO.Path;
|
||||
#else
|
||||
using System.IO;
|
||||
#endif
|
||||
|
||||
namespace ArchiSteamFarm.IPC {
|
||||
|
@ -229,9 +233,9 @@ namespace ArchiSteamFarm.IPC {
|
|||
}
|
||||
);
|
||||
|
||||
string xmlDocumentationFile = System.IO.Path.Combine(AppContext.BaseDirectory, SharedInfo.AssemblyDocumentation);
|
||||
string xmlDocumentationFile = Path.Combine(AppContext.BaseDirectory, SharedInfo.AssemblyDocumentation);
|
||||
|
||||
if (System.IO.File.Exists(xmlDocumentationFile)) {
|
||||
if (File.Exists(xmlDocumentationFile)) {
|
||||
options.IncludeXmlComments(xmlDocumentationFile);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ using System.Runtime.CompilerServices;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.RuntimeCompatibility;
|
||||
using JetBrains.Annotations;
|
||||
using NLog;
|
||||
using SteamKit2;
|
||||
|
@ -173,7 +174,7 @@ namespace ArchiSteamFarm.NLog {
|
|||
string message = string.Format(CultureInfo.CurrentCulture, DateTime.Now + " " + Strings.ErrorEarlyFatalExceptionInfo, SharedInfo.Version) + Environment.NewLine;
|
||||
|
||||
try {
|
||||
await RuntimeCompatibility.File.WriteAllTextAsync(SharedInfo.LogFile, message).ConfigureAwait(false);
|
||||
await File.WriteAllTextAsync(SharedInfo.LogFile, message).ConfigureAwait(false);
|
||||
} catch {
|
||||
// Ignored, we can't do anything about this
|
||||
}
|
||||
|
@ -188,7 +189,7 @@ namespace ArchiSteamFarm.NLog {
|
|||
message = string.Format(CultureInfo.CurrentCulture, Strings.ErrorEarlyFatalExceptionPrint, previousMethodName, exception.Message, exception.StackTrace) + Environment.NewLine;
|
||||
|
||||
try {
|
||||
await RuntimeCompatibility.File.AppendAllTextAsync(SharedInfo.LogFile, message).ConfigureAwait(false);
|
||||
await File.AppendAllTextAsync(SharedInfo.LogFile, message).ConfigureAwait(false);
|
||||
} catch {
|
||||
// Ignored, we can't do anything about this
|
||||
}
|
||||
|
|
|
@ -193,6 +193,7 @@ namespace ArchiSteamFarm {
|
|||
_ => false
|
||||
};
|
||||
#else
|
||||
|
||||
// This is .NET Core build, we support all scenarios
|
||||
return true;
|
||||
#endif
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using ArchiSteamFarm.Plugins;
|
||||
using JetBrains.Annotations;
|
||||
|
@ -74,7 +75,7 @@ namespace ArchiSteamFarm {
|
|||
// We can't just return our base directory since it could lead to the (wrong) temporary directory of extracted files in a single-publish scenario
|
||||
// If the path goes to our own binary, the user is using OS-specific build, single-file or not, we'll use path to location of that binary then
|
||||
// Otherwise, this path goes to some third-party binary, likely dotnet/mono, the user is using our generic build or other custom binary, we need to trust our base directory then
|
||||
CachedHomeDirectory = System.IO.Path.GetFileNameWithoutExtension(OS.ProcessFileName) == AssemblyName ? System.IO.Path.GetDirectoryName(OS.ProcessFileName) ?? AppContext.BaseDirectory : AppContext.BaseDirectory;
|
||||
CachedHomeDirectory = Path.GetFileNameWithoutExtension(OS.ProcessFileName) == AssemblyName ? Path.GetDirectoryName(OS.ProcessFileName) ?? AppContext.BaseDirectory : AppContext.BaseDirectory;
|
||||
|
||||
return CachedHomeDirectory;
|
||||
}
|
||||
|
|
|
@ -31,9 +31,9 @@ using System.Threading.Tasks;
|
|||
using System.Xml;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.NLog;
|
||||
using ArchiSteamFarm.RuntimeCompatibility;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using ArchiSteamFarm.RuntimeCompatibility;
|
||||
|
||||
namespace ArchiSteamFarm.Web {
|
||||
public sealed class WebBrowser : IDisposable {
|
||||
|
|
Loading…
Reference in a new issue