Changed Config System

This commit is contained in:
2022-10-25 21:37:52 +03:00
parent cad19935d5
commit 11ec02ef68
12 changed files with 584 additions and 418 deletions

View File

@@ -1,6 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using PluginManager; using PluginManager;
using PluginManager.Interfaces; using PluginManager.Interfaces;
using PluginManager.Loaders; using PluginManager.Loaders;
@@ -58,7 +60,7 @@ internal class Help : DBCommand
var embedBuilder = new EmbedBuilder(); var embedBuilder = new EmbedBuilder();
var adminCommands = ""; var adminCommands = "";
var normalCommands = ""; var normalCommands = "";
foreach (var cmd in PluginLoader.Commands!) foreach (var cmd in PluginLoader.Commands!)
@@ -79,7 +81,7 @@ internal class Help : DBCommand
(p.Aliases is not null && p.Aliases.Contains(command))); (p.Aliases is not null && p.Aliases.Contains(command)));
if (cmd == null) return null; if (cmd == null) return null;
embedBuilder.AddField("Usage", Config.GetValue<string>("prefix") + cmd.Usage); embedBuilder.AddField("Usage", Config.Variables.GetValue("prefix") + cmd.Usage);
embedBuilder.AddField("Description", cmd.Description); embedBuilder.AddField("Description", cmd.Description);
if (cmd.Aliases is null) if (cmd.Aliases is null)
return embedBuilder; return embedBuilder;

View File

@@ -1,87 +0,0 @@
using System;
using System.Collections.Generic;
using Discord.Commands;
using PluginManager;
using PluginManager.Interfaces;
namespace DiscordBot.Discord.Commands;
internal class Settings : DBCommand
{
/// <summary>
/// Command name
/// </summary>
public string Command => "set";
public List<string> Aliases => null;
/// <summary>
/// Command Description
/// </summary>
public string Description => "This command allows you change all settings. Use \"set help\" to show details";
/// <summary>
/// Command usage
/// </summary>
public string Usage => "set [keyword] [new Value]";
/// <summary>
/// Check if the command require administrator to be executed
/// </summary>
public bool requireAdmin => true;
/// <summary>
/// The main body of the command
/// </summary>
/// <param name="context">The command context</param>
public async void Execute(SocketCommandContext context)
{
var channel = context.Message.Channel;
try
{
var content = context.Message.Content;
var data = content.Split(' ');
var keyword = data[1];
if (keyword.ToLower() == "help")
{
await channel.SendMessageAsync(
"set token [new value] -- set the value of the new token (require restart)");
await channel.SendMessageAsync(
"set prefix [new value] -- set the value of the new preifx (require restart)");
return;
}
switch (keyword.ToLower())
{
case "token":
if (data.Length != 3)
{
await channel.SendMessageAsync("Invalid token !");
return;
}
Config.SetValue("token", data[2]);
break;
case "prefix":
if (data.Length != 3)
{
await channel.SendMessageAsync("Invalid token !");
return;
}
Config.SetValue("token", data[2]);
break;
default:
return;
}
await channel.SendMessageAsync("Restart required ...");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
await channel.SendMessageAsync("Unknown usage to this command !\nUsage: " + Usage);
}
}
}

View File

@@ -8,7 +8,7 @@
<StartupObject /> <StartupObject />
<SignAssembly>False</SignAssembly> <SignAssembly>False</SignAssembly>
<IsPublishable>True</IsPublishable> <IsPublishable>True</IsPublishable>
<AssemblyVersion>1.0.0.15</AssemblyVersion> <AssemblyVersion>1.0.1.0</AssemblyVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

@@ -8,6 +8,7 @@ using System.Threading.Tasks;
using DiscordBot.Discord.Core; using DiscordBot.Discord.Core;
using PluginManager; using PluginManager;
using PluginManager.Database;
using PluginManager.Items; using PluginManager.Items;
using PluginManager.Online; using PluginManager.Online;
using PluginManager.Online.Helpers; using PluginManager.Online.Helpers;
@@ -35,11 +36,12 @@ public class Program
Console.WriteLine("Loading resources ..."); Console.WriteLine("Loading resources ...");
PreLoadComponents().Wait(); PreLoadComponents().Wait();
if (!Config.ContainsKey("ServerID") || !Config.ContainsKey("token") || if (!Config.Variables.Exists("ServerID") || !Config.Variables.Exists("token") ||
Config.GetValue<string>("token") == null || Config.Variables.GetValue("token") == null ||
(Config.GetValue<string>("token")?.Length != 70 && Config.GetValue<string>("token")?.Length != 59) || (Config.Variables.GetValue("token")?.Length != 70 && Config.Variables.GetValue("token")?.Length != 59) ||
!Config.ContainsKey("prefix") || Config.GetValue<string>("prefix") == null || !Config.Variables.Exists("prefix") || Config.Variables.GetValue("prefix") == null ||
Config.GetValue<string>("prefix")?.Length != 1 || (args.Length > 0 && args[0] == "/newconfig")) Config.Variables.GetValue("prefix")?.Length != 1 ||
(args.Length == 1 && args[0] == "/reset"))
{ {
Application.Init(); Application.Init();
var top = Application.Top; var top = Application.Top;
@@ -53,15 +55,14 @@ public class Program
top.Add(win); top.Add(win);
var labelInfo = var labelInfo = new Label(
new Label(
"Configuration file not found or invalid. " + "Configuration file not found or invalid. " +
"Please fill the following fields to create a new configuration file." "Please fill the following fields to create a new configuration file."
) )
{ {
X = Pos.Center(), X = Pos.Center(),
Y = 2 Y = 2
}; };
var labelToken = new Label("Please insert your token here: ") var labelToken = new Label("Please insert your token here: ")
@@ -139,9 +140,9 @@ public class Program
} }
Config.AddValueToVariables("ServerID", (string)textFiledServerID.Text, true); Config.Variables.Add("ServerID", (string)textFiledServerID.Text, true);
Config.AddValueToVariables("token", (string)textFiledToken.Text, true); Config.Variables.Add("token", (string)textFiledToken.Text, true);
Config.AddValueToVariables("prefix", (string)textFiledPrefix.Text, true); Config.Variables.Add("prefix", (string)textFiledPrefix.Text, true);
MessageBox.Query("Discord Bot Settings", "Successfully saved config !\nJust start the bot :D", MessageBox.Query("Discord Bot Settings", "Successfully saved config !\nJust start the bot :D",
"Start :D"); "Start :D");
@@ -164,6 +165,8 @@ public class Program
var print_message = license[i++] + "\n"; var print_message = license[i++] + "\n";
for (; i < license.Count && !license[i].StartsWith("-----------"); i++) for (; i < license.Count && !license[i].StartsWith("-----------"); i++)
print_message += license[i] + "\n"; print_message += license[i] + "\n";
if (print_message.Contains("https://"))
print_message += "\n\nCTRL + Click on a link to open it";
if (MessageBox.Query("Licenses", print_message, "Next", "Quit") == 1) break; if (MessageBox.Query("Licenses", print_message, "Next", "Quit") == 1) break;
} }
} }
@@ -177,8 +180,8 @@ public class Program
}; };
win.Add(labelInfo, labelPrefix, labelServerid, labelToken); win.Add(labelInfo, labelPrefix, labelServerid, labelToken);
win.Add(textFiledToken, textFiledPrefix, textFiledServerID); win.Add(textFiledToken, textFiledPrefix, textFiledServerID, button3);
win.Add(button, button2, button3); win.Add(button, button2);
Application.Run(); Application.Run();
Application.Shutdown(); Application.Shutdown();
} }
@@ -198,7 +201,6 @@ public class Program
if (loadPluginsOnStartup) consoleCommandsHandler.HandleCommand("lp"); if (loadPluginsOnStartup) consoleCommandsHandler.HandleCommand("lp");
if (listPluginsAtStartup) consoleCommandsHandler.HandleCommand("listplugs"); if (listPluginsAtStartup) consoleCommandsHandler.HandleCommand("listplugs");
#endif #endif
Config.SaveConfig(SaveType.NORMAL).Wait();
while (true) while (true)
{ {
@@ -230,18 +232,16 @@ public class Program
Console.WriteLine(message); Console.WriteLine(message);
Console.WriteLine( Console.WriteLine(
$"Running on version: {Config.GetValue<string>("Version") ?? Assembly.GetExecutingAssembly().GetName().Version.ToString()}"); $"Running on version: {Assembly.GetExecutingAssembly().GetName().Version}");
Console.WriteLine($"Git URL: {Config.GetValue<string>("GitURL") ?? " Could not find Git URL"}"); Console.WriteLine($"Git URL: {Settings.Variables.WebsiteURL}");
Console_Utilities.WriteColorText( Console_Utilities.WriteColorText(
"&rRemember to close the bot using the ShutDown command (&ysd&r) or some settings won't be saved\n"); "&rRemember to close the bot using the ShutDown command (&ysd&r) or some settings won't be saved\n");
Console.ForegroundColor = ConsoleColor.White; Console.ForegroundColor = ConsoleColor.White;
if (Config.ContainsKey("LaunchMessage")) if (Config.Variables.Exists("LaunchMessage"))
{ Console_Utilities.WriteColorText(Config.Variables.GetValue("LaunchMessage"));
Console_Utilities.WriteColorText(Config.GetValue<string>("LaunchMessage"));
Config.RemoveKey("LaunchMessage");
}
Console_Utilities.WriteColorText( Console_Utilities.WriteColorText(
"Please note that the bot saves a backup save file every time you are using the shudown command (&ysd&c)"); "Please note that the bot saves a backup save file every time you are using the shudown command (&ysd&c)");
@@ -249,7 +249,7 @@ public class Program
try try
{ {
var token = Config.GetValue<string>("token"); var token = Config.Variables.GetValue("token");
#if DEBUG #if DEBUG
Console.WriteLine("Starting in DEBUG MODE"); Console.WriteLine("Starting in DEBUG MODE");
if (!Directory.Exists("./Data/BetaTest")) if (!Directory.Exists("./Data/BetaTest"))
@@ -259,7 +259,7 @@ public class Program
//Debug mode code... //Debug mode code...
#endif #endif
var prefix = Config.GetValue<string>("prefix"); var prefix = Config.Variables.GetValue("prefix");
var discordbooter = new Boot(token, prefix); var discordbooter = new Boot(token, prefix);
await discordbooter.Awake(); await discordbooter.Awake();
return discordbooter; return discordbooter;
@@ -303,8 +303,8 @@ public class Program
{ {
if (ex.Message == "No process is on the other end of the pipe." || (uint)ex.HResult == 0x800700E9) if (ex.Message == "No process is on the other end of the pipe." || (uint)ex.HResult == 0x800700E9)
{ {
if (!Config.ContainsKey("LaunchMessage")) if (Config.Variables.Exists("LaunchMessage"))
Config.AddValueToVariables("LaunchMessage", Config.Variables.Add("LaunchMessage",
"An error occured while closing the bot last time. Please consider closing the bot using the &rsd&c method !\nThere is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !", "An error occured while closing the bot last time. Please consider closing the bot using the &rsd&c method !\nThere is a risk of losing all data or corruption of the save file, which in some cases requires to reinstall the bot !",
false); false);
Functions.WriteErrFile(ex.ToString()); Functions.WriteErrFile(ex.ToString());
@@ -321,19 +321,28 @@ public class Program
Directory.CreateDirectory("./Data/Resources"); Directory.CreateDirectory("./Data/Resources");
Directory.CreateDirectory("./Data/Plugins"); Directory.CreateDirectory("./Data/Plugins");
Directory.CreateDirectory("./Data/PAKS"); Directory.CreateDirectory("./Data/PAKS");
await Config.LoadConfig();
if (Config.ContainsKey("DeleteLogsAtStartup")) Settings.sqlDatabase = new SqlDatabase(Functions.dataFolder + "SetDB.dat");
if (Config.GetValue<bool>("DeleteLogsAtStartup"))
await Settings.sqlDatabase.Open();
await Config.Initialize();
if (await Config.Variables.ExistsAsync("DeleteLogsAtStartup"))
if (await Config.Variables.GetValueAsync("DeleteLogsAtStartup") == "true")
foreach (var file in Directory.GetFiles("./Output/Logs/")) foreach (var file in Directory.GetFiles("./Output/Logs/"))
File.Delete(file); File.Delete(file);
var OnlineDefaultKeys = var OnlineDefaultKeys =
await ServerCom.ReadTextFromURL( await ServerCom.ReadTextFromURL(
"https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/SetupKeys"); "https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/SetupKeys");
if (!Config.ContainsKey("Version"))
Config.AddValueToVariables("Version", Assembly.GetExecutingAssembly().GetName().Version.ToString(), false); if (!await Config.Variables.ExistsAsync("Version"))
await Config.Variables.AddAsync("Version", Assembly.GetExecutingAssembly().GetName().Version.ToString(), false);
else else
Config.SetValue("Version", Assembly.GetExecutingAssembly().GetName().Version.ToString()); await Config.Variables.SetValueAsync("Version", Assembly.GetExecutingAssembly().GetName().Version.ToString());
foreach (var key in OnlineDefaultKeys) foreach (var key in OnlineDefaultKeys)
{ {
@@ -341,10 +350,9 @@ public class Program
var s = key.Split(' '); var s = key.Split(' ');
try try
{ {
if (Config.ContainsKey(s[0])) Config.SetValue(s[0], s[1]); if (await Config.Variables.ExistsAsync(s[0])) await Config.Variables.SetValueAsync(s[0], s[1]);
else else
Config.GetAndAddValueToVariable( await Config.Variables.AddAsync(s[0], s[1], s[2].ToLower() == "true");
s[0], s[1], s[2].Equals("true", StringComparison.CurrentCultureIgnoreCase));
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -366,13 +374,13 @@ public class Program
{ {
case "CurrentVersion": case "CurrentVersion":
var newVersion = s[1]; var newVersion = s[1];
if (!newVersion.Equals(Config.GetValue<string>("Version"))) if (!newVersion.Equals(await Config.Variables.GetValueAsync("Version")))
{ {
var nVer = new VersionString(newVersion.Substring(2)); var nVer = new VersionString(newVersion.Substring(2));
var cVer = new VersionString(Config.GetValue<string>("Version").Substring(2)); var cVer = new VersionString((await Config.Variables.GetValueAsync("Version")).Substring(2));
if (cVer > nVer) if (cVer > nVer)
{ {
Config.SetValue("Version", "1." + cVer.ToShortString() + " (Beta)"); await Config.Variables.SetValueAsync("Version", "1." + cVer.ToShortString() + " (Beta)");
break; break;
} }
@@ -402,7 +410,9 @@ public class Program
if (Functions.GetOperatingSystem() == OperatingSystem.LINUX) if (Functions.GetOperatingSystem() == OperatingSystem.LINUX)
break; break;
if (Config.UpdaterVersion != updaternewversion || if (!await Config.Variables.ExistsAsync("UpdaterVersion"))
await Config.Variables.AddAsync("UpdaterVersion", "0.0.0.0", false);
if (await Config.Variables.GetValueAsync("UpdaterVersion") != updaternewversion ||
!Directory.Exists("./Updater") || !Directory.Exists("./Updater") ||
!File.Exists("./Updater/Updater.exe")) !File.Exists("./Updater/Updater.exe"))
{ {
@@ -415,9 +425,8 @@ public class Program
"./Updater.zip"); "./Updater.zip");
await Functions.ExtractArchive("./Updater.zip", "./", null, await Functions.ExtractArchive("./Updater.zip", "./", null,
UnzipProgressType.PercentageFromTotalSize); UnzipProgressType.PercentageFromTotalSize);
Config.UpdaterVersion = updaternewversion; await Config.Variables.SetValueAsync("UpdaterVersion", updaternewversion);
File.Delete("Updater.zip"); File.Delete("Updater.zip");
await Config.SaveConfig(SaveType.NORMAL);
bar.Stop("Updater has been updated !"); bar.Stop("Updater has been updated !");
Console.Clear(); Console.Clear();
} }
@@ -425,10 +434,6 @@ public class Program
break; break;
} }
} }
Console_Utilities.Initialize();
await Config.SaveConfig(SaveType.NORMAL);
Console.Clear(); Console.Clear();
} }
} }

View File

@@ -1,247 +1,199 @@
using System; using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using PluginManager.Others; using PluginManager.Online.Helpers;
namespace PluginManager; namespace PluginManager;
internal class AppConfig
{
public string? UpdaterVersion { get; set; }
public Dictionary<string, object>? ApplicationVariables { get; init; }
public List<string>? ProtectedKeyWords { get; init; }
public Dictionary<string, string>? PluginVersions { get; init; }
}
public static class Config public static class Config
{ {
private static AppConfig? appConfig { get; set; } private static bool IsLoaded = false;
public static async Task Initialize()
public static string UpdaterVersion
{ {
get => appConfig!.UpdaterVersion!; if (IsLoaded)
set => appConfig!.UpdaterVersion = value;
}
public static string GetPluginVersion(string pluginName)
{
return appConfig!.PluginVersions![pluginName];
}
public static void SetPluginVersion(string pluginName, string newVersion)
{
if (appConfig!.PluginVersions!.ContainsKey(pluginName))
appConfig.PluginVersions[pluginName] = newVersion;
else appConfig.PluginVersions.Add(pluginName, newVersion);
// SaveConfig();
}
public static void RemovePluginVersion(string pluginName)
{
appConfig!.PluginVersions!.Remove(pluginName);
}
public static bool PluginVersionsContainsKey(string pluginName)
{
return appConfig!.PluginVersions!.ContainsKey(pluginName);
}
public static void AddValueToVariables<T>(string key, T value, bool isProtected)
{
if (value == null)
throw new Exception("The value cannot be null");
if (appConfig!.ApplicationVariables!.ContainsKey(key))
throw new Exception($"The key ({key}) already exists in the variables. Value {GetValue<T>(key)}");
appConfig.ApplicationVariables.Add(key, value);
if (isProtected && key != "Version")
appConfig.ProtectedKeyWords!.Add(key);
SaveConfig(SaveType.NORMAL);
}
public static Type GetVariableType(string value)
{
if (int.TryParse(value, out var intValue))
return typeof(int);
if (bool.TryParse(value, out var boolValue))
return typeof(bool);
if (float.TryParse(value, out var floatValue))
return typeof(float);
if (double.TryParse(value, out var doubleValue))
return typeof(double);
if (uint.TryParse(value, out var uintValue))
return typeof(uint);
if (long.TryParse(value, out var longValue))
return typeof(long);
if (byte.TryParse(value, out var byteValue))
return typeof(byte);
return typeof(string);
}
public static void GetAndAddValueToVariable(string key, string value, bool isReadOnly)
{
if (ContainsKey(key))
return; return;
if (int.TryParse(value, out var intValue))
AddValueToVariables(key, intValue, isReadOnly); if (!await Settings.sqlDatabase.TableExistsAsync("Plugins"))
else if (bool.TryParse(value, out var boolValue)) await Settings.sqlDatabase.CreateTableAsync("Plugins", "PluginName", "Version");
AddValueToVariables(key, boolValue, isReadOnly); if (!await Settings.sqlDatabase.TableExistsAsync("Variables"))
else if (float.TryParse(value, out var floatValue)) await Settings.sqlDatabase.CreateTableAsync("Variables", "VarName", "Value", "ReadOnly");
AddValueToVariables(key, floatValue, isReadOnly);
else if (double.TryParse(value, out var doubleValue)) IsLoaded = true;
AddValueToVariables(key, doubleValue, isReadOnly);
else if (uint.TryParse(value, out var uintValue))
AddValueToVariables(key, uintValue, isReadOnly);
else if (long.TryParse(value, out var longValue))
AddValueToVariables(key, longValue, isReadOnly);
else if (byte.TryParse(value, out var byteValue))
AddValueToVariables(key, byteValue, isReadOnly);
else
AddValueToVariables(key, value, isReadOnly);
} }
public static T? GetValue<T>(string key) public static class Variables
{ {
if (!appConfig!.ApplicationVariables!.ContainsKey(key)) return default; public static async Task<string> GetValueAsync(string VarName)
try
{ {
var element = (JsonElement)appConfig.ApplicationVariables[key]; if (!IsLoaded)
return element.Deserialize<T>(); throw new Exception("Config is not loaded");
return await Settings.sqlDatabase.GetValueAsync("Variables", "VarName", VarName, "Value");
} }
catch
public static string GetValue(string VarName)
{ {
return (T)appConfig.ApplicationVariables[key]; if (!IsLoaded)
throw new Exception("Config is not loaded");
return Settings.sqlDatabase.GetValue("Variables", "VarName", VarName, "Value");
} }
}
public static void SetValue<T>(string key, T value)
{
if (value == null)
throw new Exception("Value is null");
if (!appConfig!.ApplicationVariables!.ContainsKey(key))
throw new Exception("Key does not exist in the config file");
if (appConfig.ProtectedKeyWords!.Contains(key))
throw new Exception("Key is protected");
appConfig.ApplicationVariables[key] = JsonSerializer.SerializeToElement(value); public static async Task SetValueAsync(string VarName, string Value)
SaveConfig(SaveType.NORMAL);
}
public static bool TrySetValue<T>(string key, T value)
{
if (Config.ContainsKey(key))
{ {
try if (!IsLoaded)
throw new Exception("Config is not loaded");
if (await IsReadOnlyAsync(VarName))
throw new Exception($"Variable ({VarName}) is read only and can not be changed to {Value}");
await Settings.sqlDatabase.SetValueAsync("Variables", "VarName", VarName, "Value", Value);
}
public static void SetValue(string VarName, string Value)
{
if (!IsLoaded)
throw new Exception("Config is not loaded");
if (IsReadOnly(VarName))
throw new Exception($"Variable ({VarName}) is read only and can not be changed to {Value}");
Settings.sqlDatabase.SetValue("Variables", "VarName", VarName, "Value", Value);
}
public static async Task<bool> IsReadOnlyAsync(string VarName)
{
if (!IsLoaded)
throw new Exception("Config is not loaded");
return (await Settings.sqlDatabase.GetValueAsync("Variables", "VarName", VarName, "ReadOnly")).Equals("true", StringComparison.CurrentCultureIgnoreCase);
}
public static bool IsReadOnly(string VarName)
{
if (!IsLoaded)
throw new Exception("Config is not loaded");
return (Settings.sqlDatabase.GetValue("Variables", "VarName", VarName, "ReadOnly")).Equals("true", StringComparison.CurrentCultureIgnoreCase);
}
public static async Task SetReadOnlyAsync(string VarName, bool ReadOnly)
{
if (!IsLoaded)
throw new Exception("Config is not loaded");
await Settings.sqlDatabase.SetValueAsync("Variables", "VarName", VarName, "ReadOnly", ReadOnly ? "true" : "false");
}
public static void SetReadOnly(string VarName, bool ReadOnly)
{
if (!IsLoaded)
throw new Exception("Config is not loaded");
Settings.sqlDatabase.SetValue("Variables", "VarName", VarName, "ReadOnly", ReadOnly ? "true" : "false");
}
public static async Task<bool> ExistsAsync(string VarName)
{
if (!IsLoaded)
throw new Exception("Config is not loaded");
return await Settings.sqlDatabase.KeyExistsAsync("Variables", "VarName", VarName);
}
public static bool Exists(string VarName)
{
if (!IsLoaded)
throw new Exception("Config is not loaded");
return Settings.sqlDatabase.KeyExists("Variables", "VarName", VarName);
}
public static async Task AddAsync(string VarName, string Value, bool ReadOnly = false)
{
if (!IsLoaded)
throw new Exception("Config is not loaded");
if (await ExistsAsync(VarName))
{ {
Config.SetValue(key, value); await SetValueAsync(VarName, Value);
return true; await SetReadOnlyAsync(VarName, ReadOnly);
}
catch
{
return false;
}
}
Config.AddValueToVariables(key, value, false);
return true;
}
public static void RemoveKey(string key)
{
if (key == "Version" || key == "token" || key == "prefix")
throw new Exception("Key is protected");
appConfig!.ApplicationVariables!.Remove(key);
appConfig.ProtectedKeyWords!.Remove(key);
SaveConfig(SaveType.NORMAL);
}
public static bool IsReadOnly(string key)
{
return appConfig.ProtectedKeyWords.Contains(key);
}
public static async Task SaveConfig(SaveType type)
{
if (type == SaveType.NORMAL)
{
var path = Functions.dataFolder + "config.json";
await Functions.SaveToJsonFile(path, appConfig!);
return;
}
if (type == SaveType.BACKUP)
{
var path = Functions.dataFolder + "config.json.bak";
await Functions.SaveToJsonFile(path, appConfig!);
}
}
public static async Task LoadConfig()
{
var path = Functions.dataFolder + "config.json";
if (File.Exists(path))
{
try
{
appConfig = await Functions.ConvertFromJson<AppConfig>(path);
}
catch (Exception ex)
{
File.Delete(path);
Console.WriteLine("An error occured while loading the settings. Importing from backup file...");
path = Functions.dataFolder + "config.json.bak";
appConfig = await Functions.ConvertFromJson<AppConfig>(path);
Functions.WriteErrFile(ex.Message);
}
Functions.WriteLogFile(
$"Loaded {appConfig.ApplicationVariables!.Keys.Count} application variables.\nLoaded {appConfig.ProtectedKeyWords!.Count} readonly variables.");
return;
}
if (File.Exists(Functions.dataFolder + "config.json.bak"))
{
try
{
Console.WriteLine("An error occured while loading the settings. Importing from backup file...");
path = Functions.dataFolder + "config.json.bak";
appConfig = await Functions.ConvertFromJson<AppConfig>(path);
return; return;
} }
catch (Exception ex) await Settings.sqlDatabase.InsertAsync("Variables", VarName, Value, ReadOnly ? "true" : "false");
{
Console.WriteLine(ex.Message);
}
} }
appConfig = new AppConfig public static void Add(string VarName, string Value, bool ReadOnly = false)
{ {
ApplicationVariables = new Dictionary<string, object>(), if (!IsLoaded)
ProtectedKeyWords = new List<string>(), throw new Exception("Config is not loaded");
PluginVersions = new Dictionary<string, string>(), if (Exists(VarName))
UpdaterVersion = "-1" {
}; SetValue(VarName, Value);
SetReadOnly(VarName, ReadOnly);
return;
}
Settings.sqlDatabase.Insert("Variables", VarName, Value, ReadOnly ? "true" : "false");
}
public static async Task RemoveKeyAsync(string VarName)
{
if (!IsLoaded)
throw new Exception("Config is not loaded");
await Settings.sqlDatabase.RemoveKeyAsync("Variables", "VarName", VarName);
}
public static void RemoveKey(string VarName)
{
if (!IsLoaded)
throw new Exception("Config is not loaded");
Settings.sqlDatabase.RemoveKey("Variables", "VarName", VarName);
}
} }
public static bool ContainsValue<T>(T value) public static class Plugins
{ {
return appConfig!.ApplicationVariables!.ContainsValue(value!); public static async Task<string> GetVersionAsync(string pluginName)
} {
if (!IsLoaded)
throw new Exception("Config is not loaded yet");
public static bool ContainsKey(string key) string result = await Settings.sqlDatabase.GetValueAsync("Plugins", "PluginName", pluginName, "Version");
{ if (result is null)
return appConfig!.ApplicationVariables!.ContainsKey(key); return "0.0.0";
}
return result;
}
public static string GetVersion(string pluginName)
{
if (!IsLoaded)
throw new Exception("Config is not loaded yet");
string result = Settings.sqlDatabase.GetValue("Plugins", "PluginName", pluginName, "Version");
if (result is null)
return "0.0.0";
return result;
}
public static async Task SetVersionAsync(string pluginName, VersionString version)
{
if (!IsLoaded)
throw new Exception("Config is not loaded yet");
if (!await Settings.sqlDatabase.KeyExistsAsync("Plugins", "PluginName", pluginName))
{
await Settings.sqlDatabase.InsertAsync("Plugins", pluginName, version.ToShortString());
return;
}
await Settings.sqlDatabase.SetValueAsync("Plugins", "PluginName", pluginName, "Version", version.ToShortString());
}
public static void SetVersion(string pluginName, VersionString version)
{
if (!IsLoaded)
throw new Exception("Config is not loaded yet");
if (!Settings.sqlDatabase.KeyExists("Plugins", "PluginName", pluginName))
{
Settings.sqlDatabase.Insert("Plugins", pluginName, version.ToShortString());
return;
}
Settings.sqlDatabase.SetValue("Plugins", "PluginName", pluginName, "Version", version.ToShortString());
}
public static IDictionary<string, object>? GetAllVariables()
{
return appConfig?.ApplicationVariables;
} }
} }

View File

@@ -0,0 +1,310 @@
using System.Collections.Generic;
using System.Data.SQLite;
using System.IO;
using System.Threading.Tasks;
namespace PluginManager.Database
{
public class SqlDatabase
{
private string ConnectionString;
private SQLiteConnection Connection;
public SqlDatabase(string fileName)
{
if (!File.Exists(fileName))
SQLiteConnection.CreateFile(fileName);
ConnectionString = $"URI=file:{fileName}";
Connection = new SQLiteConnection(ConnectionString);
}
public async Task Open()
{
await Connection.OpenAsync();
//Console.WriteLine("Opened database successfully");
}
public async Task InsertAsync(string tableName, params string[] values)
{
string query = $"INSERT INTO {tableName} VALUES (";
for (int i = 0; i < values.Length; i++)
{
query += $"'{values[i]}'";
if (i != values.Length - 1)
query += ", ";
}
query += ")";
SQLiteCommand command = new SQLiteCommand(query, Connection);
await command.ExecuteNonQueryAsync();
}
public void Insert(string tableName, params string[] values)
{
string query = $"INSERT INTO {tableName} VALUES (";
for (int i = 0; i < values.Length; i++)
{
query += $"'{values[i]}'";
if (i != values.Length - 1)
query += ", ";
}
query += ")";
SQLiteCommand command = new SQLiteCommand(query, Connection);
command.ExecuteNonQuery();
}
public async Task RemoveKeyAsync(string tableName, string KeyName, string KeyValue)
{
string query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'";
SQLiteCommand command = new SQLiteCommand(query, Connection);
await command.ExecuteNonQueryAsync();
}
public void RemoveKey(string tableName, string KeyName, string KeyValue)
{
string query = $"DELETE FROM {tableName} WHERE {KeyName} = '{KeyValue}'";
SQLiteCommand command = new SQLiteCommand(query, Connection);
command.ExecuteNonQuery();
}
public async Task<bool> KeyExistsAsync(string tableName, string keyName, string KeyValue)
{
string query = $"SELECT * FROM {tableName} where {keyName} = '{KeyValue}'";
if (await ReadDataAsync(query) is not null)
return true;
return false;
}
public bool KeyExists(string tableName, string keyName, string KeyValue)
{
string query = $"SELECT * FROM {tableName} where {keyName} = '{KeyValue}'";
if (ReadData(query) is not null)
return true;
return false;
}
public async Task SetValueAsync(string tableName, string keyName, string KeyValue, string ResultColumnName, string ResultColumnValue)
{
if (!await TableExistsAsync(tableName))
throw new System.Exception($"Table {tableName} does not exist");
await ExecuteAsync($"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'");
}
public void SetValue(string tableName, string keyName, string KeyValue, string ResultColumnName, string ResultColumnValue)
{
if (!TableExists(tableName))
throw new System.Exception($"Table {tableName} does not exist");
Execute($"UPDATE {tableName} SET {ResultColumnName}='{ResultColumnValue}' WHERE {keyName}='{KeyValue}'");
}
public async Task<string> GetValueAsync(string tableName, string keyName, string KeyValue, string ResultColumnName)
{
if (!await TableExistsAsync(tableName))
throw new System.Exception($"Table {tableName} does not exist");
return await ReadDataAsync($"SELECT {ResultColumnName} FROM {tableName} WHERE {keyName}='{KeyValue}'");
}
public string GetValue(string tableName, string keyName, string KeyValue, string ResultColumnName)
{
if (!TableExists(tableName))
throw new System.Exception($"Table {tableName} does not exist");
return ReadData($"SELECT {ResultColumnName} FROM {tableName} WHERE {keyName}='{KeyValue}'");
}
public async void Stop()
{
await Connection.CloseAsync();
}
public async Task AddColumnsToTableAsync(string tableName, string[] columns)
{
var command = Connection.CreateCommand();
command.CommandText = $"SELECT * FROM {tableName}";
var reader = await command.ExecuteReaderAsync();
var tableColumns = new List<string>();
for (int i = 0; i < reader.FieldCount; i++)
tableColumns.Add(reader.GetName(i));
foreach (var column in columns)
{
if (!tableColumns.Contains(column))
{
command.CommandText = $"ALTER TABLE {tableName} ADD COLUMN {column} TEXT";
await command.ExecuteNonQueryAsync();
}
}
}
public void AddColumnsToTable(string tableName, string[] columns)
{
var command = Connection.CreateCommand();
command.CommandText = $"SELECT * FROM {tableName}";
var reader = command.ExecuteReader();
var tableColumns = new List<string>();
for (int i = 0; i < reader.FieldCount; i++)
tableColumns.Add(reader.GetName(i));
foreach (var column in columns)
{
if (!tableColumns.Contains(column))
{
command.CommandText = $"ALTER TABLE {tableName} ADD COLUMN {column} TEXT";
command.ExecuteNonQuery();
}
}
}
public async Task<bool> TableExistsAsync(string tableName)
{
var cmd = Connection.CreateCommand();
cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'";
var result = await cmd.ExecuteScalarAsync();
if (result == null)
return false;
return true;
}
public bool TableExists(string tableName)
{
var cmd = Connection.CreateCommand();
cmd.CommandText = $"SELECT name FROM sqlite_master WHERE type='table' AND name='{tableName}'";
var result = cmd.ExecuteScalar();
if (result == null)
return false;
return true;
}
public async Task CreateTableAsync(string tableName, params string[] columns)
{
var cmd = Connection.CreateCommand();
cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})";
await cmd.ExecuteNonQueryAsync();
}
public void CreateTable(string tableName, params string[] columns)
{
var cmd = Connection.CreateCommand();
cmd.CommandText = $"CREATE TABLE IF NOT EXISTS {tableName} ({string.Join(", ", columns)})";
cmd.ExecuteNonQuery();
}
public async Task<int> ExecuteAsync(string query)
{
if (!Connection.State.HasFlag(System.Data.ConnectionState.Open))
await Connection.OpenAsync();
var command = new SQLiteCommand(query, Connection);
int answer = await command.ExecuteNonQueryAsync();
return answer;
}
public int Execute(string query)
{
if (!Connection.State.HasFlag(System.Data.ConnectionState.Open))
Connection.Open();
var command = new SQLiteCommand(query, Connection);
int r = command.ExecuteNonQuery();
return r;
}
public async Task<string> ReadDataAsync(string query)
{
if (!Connection.State.HasFlag(System.Data.ConnectionState.Open))
await Connection.OpenAsync();
var command = new SQLiteCommand(query, Connection);
var reader = await command.ExecuteReaderAsync();
object[] values = new object[reader.FieldCount];
if (reader.Read())
{
reader.GetValues(values);
return string.Join<object>(" ", values);
}
return null;
}
public string ReadData(string query)
{
if (!Connection.State.HasFlag(System.Data.ConnectionState.Open))
Connection.Open();
var command = new SQLiteCommand(query, Connection);
var reader = command.ExecuteReader();
object[] values = new object[reader.FieldCount];
if (reader.Read())
{
reader.GetValues(values);
return string.Join<object>(" ", values);
}
return null;
}
public async Task<object[]> ReadDataArrayAsync(string query)
{
if (!Connection.State.HasFlag(System.Data.ConnectionState.Open))
await Connection.OpenAsync();
var command = new SQLiteCommand(query, Connection);
var reader = await command.ExecuteReaderAsync();
object[] values = new object[reader.FieldCount];
if (reader.Read())
{
reader.GetValues(values);
return values;
}
return null;
}
public object[] ReadDataArray(string query)
{
if (!Connection.State.HasFlag(System.Data.ConnectionState.Open))
Connection.Open();
var command = new SQLiteCommand(query, Connection);
var reader = command.ExecuteReader();
object[] values = new object[reader.FieldCount];
if (reader.Read())
{
reader.GetValues(values);
return values;
}
return null;
}
}
}

View File

@@ -254,8 +254,7 @@ public class ConsoleCommandsHandler
var ver = await ServerCom.GetVersionOfPackageFromWeb(name); var ver = await ServerCom.GetVersionOfPackageFromWeb(name);
if (ver is null) throw new Exception("Incorrect version"); if (ver is null) throw new Exception("Incorrect version");
Config.SetPluginVersion( await Config.Plugins.SetVersionAsync(name, ver);
name, $"{ver.PackageVersionID}.{ver.PackageMainVersion}.{ver.PackageCheckVersion}");
isDownloading = false; isDownloading = false;
} }
@@ -266,10 +265,10 @@ public class ConsoleCommandsHandler
{ {
if (args.Length != 2) if (args.Length != 2)
return; return;
if (!Config.ContainsKey(args[1])) if (!Config.Variables.Exists(args[1]))
return; return;
var data = Config.GetValue<string>(args[1]); var data = Config.Variables.GetValue(args[1]);
Console.WriteLine($"{args[1]} => {data}"); Console.WriteLine($"{args[1]} => {data}");
} }
); );
@@ -284,7 +283,7 @@ public class ConsoleCommandsHandler
try try
{ {
Config.GetAndAddValueToVariable(key, value, isReadOnly); Config.Variables.Add(key, value, isReadOnly);
Console.WriteLine($"Updated config file with the following command: {args[1]} => {value}"); Console.WriteLine($"Updated config file with the following command: {args[1]} => {value}");
} }
catch (Exception ex) catch (Exception ex)
@@ -298,7 +297,7 @@ public class ConsoleCommandsHandler
{ {
if (args.Length < 2) if (args.Length < 2)
return; return;
Config.RemoveKey(args[1]); Config.Variables.RemoveKey(args[1]);
} }
); );
@@ -309,10 +308,9 @@ public class ConsoleCommandsHandler
var bar = new Console_Utilities.ProgressBar(ProgressBarType.NO_END); var bar = new Console_Utilities.ProgressBar(ProgressBarType.NO_END);
bar.Start(); bar.Start();
await Config.SaveConfig(SaveType.NORMAL);
await Config.SaveConfig(SaveType.BACKUP);
bar.Stop("Saved config !"); bar.Stop("Saved config !");
Console.WriteLine(); Console.WriteLine();
Settings.sqlDatabase.Stop();
await client.StopAsync(); await client.StopAsync();
await client.DisposeAsync(); await client.DisposeAsync();

View File

@@ -80,20 +80,14 @@ public class PluginLoader
var version = await ServerCom.GetVersionOfPackageFromWeb(name); var version = await ServerCom.GetVersionOfPackageFromWeb(name);
if (version is null) if (version is null)
return; return;
if (!Config.PluginVersionsContainsKey(name)) if (Config.Plugins.GetVersion(name) is not null)
Config.SetPluginVersion( Config.Plugins.SetVersion(name, version);
name, (version.PackageVersionID + ".0.0"));
if (await PluginUpdater.CheckForUpdates(name)) if (await PluginUpdater.CheckForUpdates(name))
await PluginUpdater.Download(name); await PluginUpdater.Download(name);
}); });
//Save the new config file (after the updates)
await Config.SaveConfig(SaveType.NORMAL);
//Load all plugins //Load all plugins
Commands = new List<DBCommand>(); Commands = new List<DBCommand>();
@@ -103,23 +97,6 @@ public class PluginLoader
Functions.WriteLogFile("Starting plugin loader ... Client: " + _client.CurrentUser.Username); Functions.WriteLogFile("Starting plugin loader ... Client: " + _client.CurrentUser.Username);
Console.WriteLine("Loading plugins"); Console.WriteLine("Loading plugins");
/* var commandsLoader = new Loader<DBCommand>(pluginCMDFolder, pluginCMDExtension);
var eventsLoader = new Loader<DBEvent>(pluginEVEFolder, pluginEVEExtension);
var slashLoader = new Loader<DBSlashCommand>("./Data/Plugins/SlashCommands/", "dll");
commandsLoader.FileLoaded += OnCommandFileLoaded;
commandsLoader.PluginLoaded += OnCommandLoaded;
eventsLoader.FileLoaded += EventFileLoaded;
eventsLoader.PluginLoaded += OnEventLoaded;
slashLoader.FileLoaded += SlashLoader_FileLoaded;
slashLoader.PluginLoaded += SlashLoader_PluginLoaded;
Commands = commandsLoader.Load();
Events = eventsLoader.Load();
SlashCommands = slashLoader.Load();*/
var loader = new LoaderV2("./Data/Plugins", "dll"); var loader = new LoaderV2("./Data/Plugins", "dll");
loader.FileLoaded += (args) => Functions.WriteLogFile($"{args.PluginName} file Loaded"); loader.FileLoaded += (args) => Functions.WriteLogFile($"{args.PluginName} file Loaded");
loader.PluginLoaded += Loader_PluginLoaded; loader.PluginLoaded += Loader_PluginLoaded;

View File

@@ -91,9 +91,9 @@ public static class ServerCom
public static VersionString? GetVersionOfPackage(string pakName) public static VersionString? GetVersionOfPackage(string pakName)
{ {
if (!Config.PluginVersionsContainsKey(pakName)) if (Config.Plugins.GetVersion(pakName) is null)
return null; return null;
return new VersionString(Config.GetPluginVersion(pakName)); return new VersionString(Config.Plugins.GetVersion(pakName));
} }
public static async Task<VersionString?> GetVersionOfPackageFromWeb(string pakName) public static async Task<VersionString?> GetVersionOfPackageFromWeb(string pakName)

View File

@@ -6,25 +6,16 @@ namespace PluginManager.Others;
public static class Console_Utilities public static class Console_Utilities
{ {
public static void Initialize() private static Dictionary<char, ConsoleColor> Colors = new()
{ {
if (!Config.ContainsKey("TableVariables"))
Config.AddValueToVariables("TableVariables", new Dictionary<string, string> { { "DefaultSpace", "3" } },
false);
if (!Config.ContainsKey("ColorDataBase"))
Config.AddValueToVariables("ColorDataBase", new Dictionary<char, ConsoleColor>
{
{ 'g', ConsoleColor.Green }, { 'g', ConsoleColor.Green },
{ 'b', ConsoleColor.Blue }, { 'b', ConsoleColor.Blue },
{ 'r', ConsoleColor.Red }, { 'r', ConsoleColor.Red },
{ 'm', ConsoleColor.Magenta }, { 'm', ConsoleColor.Magenta },
{ 'y', ConsoleColor.Yellow } { 'y', ConsoleColor.Yellow }
}, false };
);
if (!Config.ContainsKey("ColorPrefix")) private static char ColorPrefix = '&';
Config.AddValueToVariables("ColorPrefix", '&', false);
}
private static bool CanAproximateTo(this float f, float y) private static bool CanAproximateTo(this float f, float y)
@@ -41,9 +32,9 @@ public static class Console_Utilities
{ {
if (format == TableFormat.CENTER_EACH_COLUMN_BASED) if (format == TableFormat.CENTER_EACH_COLUMN_BASED)
{ {
var tableLine = '-'; var tableLine = '-';
var tableCross = '+'; var tableCross = '+';
var tableWall = '|'; var tableWall = '|';
var len = new int[data[0].Length]; var len = new int[data[0].Length];
foreach (var line in data) foreach (var line in data)
@@ -150,12 +141,11 @@ public static class Console_Utilities
if (format == TableFormat.DEFAULT) if (format == TableFormat.DEFAULT)
{ {
var widths = new int[data[0].Length]; var widths = new int[data[0].Length];
var space_between_columns = var space_between_columns = 3;
int.Parse(Config.GetValue<Dictionary<string, string>>("TableVariables")?["DefaultSpace"]!);
for (var i = 0; i < data.Count; i++) for (var i = 0; i < data.Count; i++)
for (var j = 0; j < data[i].Length; j++) for (var j = 0; j < data[i].Length; j++)
if (data[i][j].Length > widths[j]) if (data[i][j].Length > widths[j])
widths[j] = data[i][j].Length; widths[j] = data[i][j].Length;
for (var i = 0; i < data.Count; i++) for (var i = 0; i < data.Count; i++)
{ {
@@ -180,16 +170,15 @@ public static class Console_Utilities
public static void WriteColorText(string text, bool appendNewLineAtEnd = true) public static void WriteColorText(string text, bool appendNewLineAtEnd = true)
{ {
var initialForeGround = Console.ForegroundColor; var initialForeGround = Console.ForegroundColor;
var input = text.ToCharArray(); var input = text.ToCharArray();
for (var i = 0; i < input.Length; i++) for (var i = 0; i < input.Length; i++)
if (input[i] == Config.GetValue<char>("ColorPrefix")) if (input[i] == ColorPrefix)
{ {
if (i + 1 < input.Length) if (i + 1 < input.Length)
{ {
if (Config.GetValue<Dictionary<char, ConsoleColor>>("ColorDataBase")!.ContainsKey(input[i + 1])) if (Colors.ContainsKey(input[i + 1]))
{ {
Console.ForegroundColor = Console.ForegroundColor = Colors[input[i + 1]];
Config.GetValue<Dictionary<char, ConsoleColor>>("ColorDataBase")![input[i + 1]];
i++; i++;
} }
else if (input[i + 1] == 'c') else if (input[i + 1] == 'c')
@@ -218,7 +207,7 @@ public static class Console_Utilities
private readonly int BarLength = 32; private readonly int BarLength = 32;
private bool isRunning; private bool isRunning;
private int position = 1; private int position = 1;
private bool positive = true; private bool positive = true;
public ProgressBar(ProgressBarType type) public ProgressBar(ProgressBarType type)
@@ -226,10 +215,10 @@ public static class Console_Utilities
this.type = type; this.type = type;
} }
public float Max { get; init; } public float Max { get; init; }
public ConsoleColor Color { get; init; } public ConsoleColor Color { get; init; }
public bool NoColor { get; init; } public bool NoColor { get; init; }
public ProgressBarType type { get; set; } public ProgressBarType type { get; set; }
public int TotalLength { get; private set; } public int TotalLength { get; private set; }
@@ -345,18 +334,18 @@ public static class Console_Utilities
for (var i = 0; i < onechunk * progress; i++) for (var i = 0; i < onechunk * progress; i++)
{ {
Console.BackgroundColor = NoColor ? ConsoleColor.Black : Color; Console.BackgroundColor = NoColor ? ConsoleColor.Black : Color;
Console.CursorLeft = position++; Console.CursorLeft = position++;
Console.Write("#"); Console.Write("#");
} }
for (var i = position; i < BarLength; i++) for (var i = position; i < BarLength; i++)
{ {
Console.BackgroundColor = NoColor ? ConsoleColor.Black : ConsoleColor.DarkGray; Console.BackgroundColor = NoColor ? ConsoleColor.Black : ConsoleColor.DarkGray;
Console.CursorLeft = position++; Console.CursorLeft = position++;
Console.Write(" "); Console.Write(" ");
} }
Console.CursorLeft = BarLength + 4; Console.CursorLeft = BarLength + 4;
Console.BackgroundColor = ConsoleColor.Black; Console.BackgroundColor = ConsoleColor.Black;
if (progress.CanAproximateTo(Max)) if (progress.CanAproximateTo(Max))
Console.Write(progress + " % ✓"); Console.Write(progress + " % ✓");

View File

@@ -17,6 +17,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Discord.Net" Version="3.7.2" /> <PackageReference Include="Discord.Net" Version="3.7.2" />
<PackageReference Include="System.Data.SQLite" Version="1.0.116" />
<PackageReference Include="Terminal.Gui" Version="1.8.2" /> <PackageReference Include="Terminal.Gui" Version="1.8.2" />
</ItemGroup> </ItemGroup>

View File

@@ -0,0 +1,19 @@
using PluginManager.Database;
using PluginManager.Others;
namespace PluginManager
{
public class Settings
{
public static class Variables
{
public static string WebsiteURL = "https://wizzy69.github.io/SethDiscordBot";
public static string UpdaterURL = "https://github.com/Wizzy69/installer/releases/download/release-1-discordbot/Updater.zip";
}
public static SqlDatabase sqlDatabase;
}
}