- Unhandled exception handler added - it creates a log message.
- config.backup.xml file created and used in case config.xml is corrupted - LocalSettings.Assign() function avoided - static LocalSettins LocalSettings.Load(string fname) returns a reference to settings
This commit is contained in:
parent
9fa72109da
commit
fc30e160fc
@ -18,8 +18,9 @@ namespace TBF
|
||||
/// </summary>
|
||||
public BenchesDlg()
|
||||
{
|
||||
localSettings = new LocalSettings();
|
||||
localSettings.Assign(Program.LocalSettings);
|
||||
Program.LocalSettings.Save();
|
||||
localSettings = LocalSettings.Load(Program.LocalSettingsFileName);
|
||||
if (localSettings == null) throw new Exception("Cannot load local settings");
|
||||
|
||||
InitializeComponent();
|
||||
RedrawTestBenchesListBox();
|
||||
@ -28,12 +29,12 @@ namespace TBF
|
||||
void RedrawTestBenchesListBox()
|
||||
{
|
||||
testBenchesListBox.Items.Clear();
|
||||
if (localSettings.testBenches != null)
|
||||
if (localSettings.TestBenches != null)
|
||||
{
|
||||
int nrBenches = localSettings.testBenches.GetLength(0);
|
||||
int nrBenches = localSettings.TestBenches.GetLength(0);
|
||||
for (int i = 0; i < nrBenches; i++)
|
||||
{
|
||||
testBenchesListBox.Items.Add(localSettings.testBenches[i].BenchName);
|
||||
testBenchesListBox.Items.Add(localSettings.TestBenches[i].BenchName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -51,22 +52,22 @@ namespace TBF
|
||||
if (dr == DialogResult.OK)
|
||||
{
|
||||
int nrBenches =
|
||||
(localSettings.testBenches == null) ? 0 : localSettings.testBenches.GetLength(0);
|
||||
(localSettings.TestBenches == null) ? 0 : localSettings.TestBenches.GetLength(0);
|
||||
|
||||
if (nrBenches == 0)
|
||||
{
|
||||
localSettings.testBenches = new DatabaseSettings[1];
|
||||
localSettings.testBenches[0] = bench;
|
||||
localSettings.TestBenches = new DatabaseSettings[1];
|
||||
localSettings.TestBenches[0] = bench;
|
||||
}
|
||||
else
|
||||
{
|
||||
DatabaseSettings[] newTestBenches = new DatabaseSettings[nrBenches + 1];
|
||||
for (int i = 0; i < nrBenches; i++)
|
||||
{
|
||||
newTestBenches[i] = localSettings.testBenches[i];
|
||||
newTestBenches[i] = localSettings.TestBenches[i];
|
||||
}
|
||||
newTestBenches[nrBenches] = bench;
|
||||
localSettings.testBenches = newTestBenches;
|
||||
localSettings.TestBenches = newTestBenches;
|
||||
}
|
||||
|
||||
testBenchesListBox.Items.Add(bench.BenchName);
|
||||
@ -83,7 +84,7 @@ namespace TBF
|
||||
{
|
||||
if (testBenchesListBox.SelectedIndex >= 0)
|
||||
{
|
||||
DatabaseSettings ori = localSettings.testBenches[testBenchesListBox.SelectedIndex];
|
||||
DatabaseSettings ori = localSettings.TestBenches[testBenchesListBox.SelectedIndex];
|
||||
DatabaseSettings bench = (DatabaseSettings)ori.Clone();
|
||||
|
||||
DatabaseSettingsDlg dlg = new DatabaseSettingsDlg(bench);
|
||||
@ -91,15 +92,15 @@ namespace TBF
|
||||
if (dr == DialogResult.OK)
|
||||
{
|
||||
int nrBenches =
|
||||
(localSettings.testBenches == null) ? 0 : localSettings.testBenches.GetLength(0);
|
||||
(localSettings.TestBenches == null) ? 0 : localSettings.TestBenches.GetLength(0);
|
||||
|
||||
DatabaseSettings[] newTestBenches = new DatabaseSettings[nrBenches + 1];
|
||||
for (int i = 0; i < nrBenches; i++)
|
||||
{
|
||||
newTestBenches[i] = localSettings.testBenches[i];
|
||||
newTestBenches[i] = localSettings.TestBenches[i];
|
||||
}
|
||||
newTestBenches[nrBenches] = bench;
|
||||
localSettings.testBenches = newTestBenches;
|
||||
localSettings.TestBenches = newTestBenches;
|
||||
|
||||
testBenchesListBox.Items.Add(bench.BenchName);
|
||||
}
|
||||
@ -115,13 +116,13 @@ namespace TBF
|
||||
{
|
||||
if (testBenchesListBox.SelectedIndex >= 0)
|
||||
{
|
||||
DatabaseSettingsDlg dlg = new DatabaseSettingsDlg(localSettings.testBenches[testBenchesListBox.SelectedIndex]);
|
||||
DatabaseSettingsDlg dlg = new DatabaseSettingsDlg(localSettings.TestBenches[testBenchesListBox.SelectedIndex]);
|
||||
DialogResult dr = dlg.ShowDialog();
|
||||
if (dr == DialogResult.OK)
|
||||
{
|
||||
// Update the item name
|
||||
testBenchesListBox.Items[testBenchesListBox.SelectedIndex] =
|
||||
localSettings.testBenches[testBenchesListBox.SelectedIndex].BenchName;
|
||||
localSettings.TestBenches[testBenchesListBox.SelectedIndex].BenchName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -137,24 +138,24 @@ namespace TBF
|
||||
if (selectedIx >= 0)
|
||||
{
|
||||
int nrBenches =
|
||||
(localSettings.testBenches == null) ? 0 : localSettings.testBenches.GetLength(0);
|
||||
(localSettings.TestBenches == null) ? 0 : localSettings.TestBenches.GetLength(0);
|
||||
|
||||
if (nrBenches == 1)
|
||||
{
|
||||
localSettings.testBenches = null;
|
||||
localSettings.TestBenches = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
DatabaseSettings[] newTestBenches = new DatabaseSettings[nrBenches - 1];
|
||||
for (int i = 0; i < selectedIx; i++)
|
||||
{
|
||||
newTestBenches[i] = localSettings.testBenches[i];
|
||||
newTestBenches[i] = localSettings.TestBenches[i];
|
||||
}
|
||||
for (int i = selectedIx + 1; i < nrBenches; i++)
|
||||
{
|
||||
newTestBenches[i - 1] = localSettings.testBenches[i];
|
||||
newTestBenches[i - 1] = localSettings.TestBenches[i];
|
||||
}
|
||||
localSettings.testBenches = newTestBenches;
|
||||
localSettings.TestBenches = newTestBenches;
|
||||
}
|
||||
|
||||
RedrawTestBenchesListBox();
|
||||
@ -168,7 +169,8 @@ namespace TBF
|
||||
/// <param name="e">Not used</param>
|
||||
private void okButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Program.LocalSettings.Assign(localSettings); // Update Program.localSettings
|
||||
localSettings.Save();
|
||||
Program.LocalSettings = LocalSettings.Load(Program.LocalSettingsFileName);
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
return;
|
||||
|
||||
@ -37,13 +37,10 @@ namespace TBF
|
||||
/// Names and database settings of test benches.
|
||||
/// </summary>
|
||||
[XmlArrayAttribute("TestBenches")]
|
||||
public DatabaseSettings[] testBenches;
|
||||
public DatabaseSettings[] TestBenches;
|
||||
|
||||
[XmlIgnore]
|
||||
public DatabaseSettings[] TestBenches { get { return testBenches; } }
|
||||
|
||||
[XmlIgnore]
|
||||
public int BenchesCount { get { return (testBenches != null) ? testBenches.GetLength(0) : 0; } }
|
||||
public int BenchesCount { get { return (TestBenches != null) ? TestBenches.GetLength(0) : 0; } }
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected bench name (local or remote) or null (= no selection done).
|
||||
@ -149,115 +146,6 @@ namespace TBF
|
||||
[XmlIgnore]
|
||||
public int RsltsCombinedClmnCount { get { return (RsltsCombinedClmnWdths != null) ? RsltsCombinedClmnWdths.Length : 0; } }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Copy public fields from a LocalSettings object to this object.
|
||||
/// </summary>
|
||||
/// <param name="ls">Origin</param>
|
||||
public void Assign(LocalSettings ls)
|
||||
{
|
||||
if (ls != null)
|
||||
{
|
||||
Language = ls.Language;
|
||||
|
||||
testBenches = new DatabaseSettings[ls.BenchesCount];
|
||||
for (int i = 0; i < BenchesCount; i++)
|
||||
testBenches[i] = ls.testBenches[i];
|
||||
LastBenchName = ls.LastBenchName;
|
||||
LastProcedureName = ls.LastProcedureName;
|
||||
BatchNr = ls.BatchNr;
|
||||
|
||||
MainWndLeft = ls.MainWndLeft;
|
||||
MainWndTop = ls.MainWndTop;
|
||||
MainWndWidth = ls.MainWndWidth;
|
||||
MainWndHeight = ls.MainWndHeight;
|
||||
ManiWndMaximized = ls.ManiWndMaximized;
|
||||
|
||||
RightPaneHorizSplitterDistance = ls.RightPaneHorizSplitterDistance;
|
||||
|
||||
ComponentsDlgLeft = ls.ComponentsDlgLeft;
|
||||
ComponentsDlgTop = ls.ComponentsDlgTop;
|
||||
ComponentsDlgWidth = ls.ComponentsDlgWidth;
|
||||
ComponentsDlgHeight = ls.ComponentsDlgHeight;
|
||||
|
||||
PathsDlgLeft = ls.PathsDlgLeft;
|
||||
PathsDlgTop = ls.PathsDlgTop;
|
||||
PathsDlgWidth = ls.PathsDlgWidth;
|
||||
PathsDlgHeight = ls.PathsDlgHeight;
|
||||
|
||||
FeedingColumnWidths = new int[ls.FeedingColumnCount];
|
||||
for (int i = 0; i < FeedingColumnCount; i++)
|
||||
FeedingColumnWidths[i] = ls.FeedingColumnWidths[i];
|
||||
BenchColumnWidths = new int[ls.BenchColumnCount];
|
||||
for (int i = 0; i < BenchColumnCount; i++)
|
||||
BenchColumnWidths[i] = ls.BenchColumnWidths[i];
|
||||
OutputColumnWidths = new int[ls.OutputColumnCount];
|
||||
for (int i = 0; i < OutputColumnCount; i++)
|
||||
OutputColumnWidths[i] = ls.OutputColumnWidths[i];
|
||||
MetersColumnWidths = new int[ls.MetersColumnCount];
|
||||
for (int i = 0; i < MetersColumnCount; i++)
|
||||
MetersColumnWidths[i] = ls.MetersColumnWidths[i];
|
||||
|
||||
TransitionsDlgLeft = ls.TransitionsDlgLeft;
|
||||
TransitionsDlgTop = ls.TransitionsDlgTop;
|
||||
TransitionsDlgWidth = ls.TransitionsDlgWidth;
|
||||
TransitionsDlgHeight = ls.TransitionsDlgHeight;
|
||||
|
||||
TransitionsColumnWidths = new int[ls.TransitionsColumnCount];
|
||||
for (int i = 0; i < TransitionsColumnCount; i++)
|
||||
TransitionsColumnWidths[i] = ls.TransitionsColumnWidths[i];
|
||||
|
||||
MetrologyDlgLeft = ls.MetrologyDlgLeft;
|
||||
MetrologyDlgTop = ls.MetrologyDlgTop;
|
||||
MetrologyDlgWidth = ls.MetrologyDlgWidth;
|
||||
MetrologyDlgHeight = ls.MetrologyDlgHeight;
|
||||
|
||||
ProceduresDlgLeft = ls.ProceduresDlgLeft;
|
||||
ProceduresDlgTop = ls.ProceduresDlgTop;
|
||||
ProceduresDlgWidth = ls.ProceduresDlgWidth;
|
||||
ProceduresDlgHeight = ls.ProceduresDlgHeight;
|
||||
|
||||
OneProcedureDlgLeft = ls.OneProcedureDlgLeft;
|
||||
OneProcedureDlgTop = ls.OneProcedureDlgTop;
|
||||
OneProcedureDlgWidth = ls.OneProcedureDlgWidth;
|
||||
OneProcedureDlgHeight = ls.OneProcedureDlgHeight;
|
||||
|
||||
ResultsConfigMeters = ls.ResultsConfigMeters;
|
||||
ResultsConfigTests = ls.ResultsConfigTests;
|
||||
|
||||
int count = (ls.RsltItems_Screen_SingleWM != null) ? ls.RsltItems_Screen_SingleWM.Length : 0;
|
||||
RsltItems_Screen_SingleWM = new string[count];
|
||||
for (int i = 0; i < count; i++) RsltItems_Screen_SingleWM[i] = ls.RsltItems_Screen_SingleWM[i];
|
||||
|
||||
count = (ls.RsltItems_Screen_CombinedWM != null) ? ls.RsltItems_Screen_CombinedWM.Length : 0;
|
||||
RsltItems_Screen_CombinedWM = new string[count];
|
||||
for (int i = 0; i < count; i++) RsltItems_Screen_CombinedWM[i] = ls.RsltItems_Screen_CombinedWM[i];
|
||||
|
||||
count = (ls.RsltItems_Printer_SingleWM != null) ? ls.RsltItems_Printer_SingleWM.Length : 0;
|
||||
RsltItems_Printer_SingleWM = new string[count];
|
||||
for (int i = 0; i < count; i++) RsltItems_Printer_SingleWM[i] = ls.RsltItems_Printer_SingleWM[i];
|
||||
|
||||
count = (ls.RsltItems_Printer_CombinedWM != null) ? ls.RsltItems_Printer_CombinedWM.Length : 0;
|
||||
RsltItems_Printer_CombinedWM = new string[count];
|
||||
for (int i = 0; i < count; i++) RsltItems_Printer_CombinedWM[i] = ls.RsltItems_Printer_CombinedWM[i];
|
||||
|
||||
count = (ls.RsltItems_Disk_SingleWM != null) ? ls.RsltItems_Disk_SingleWM.Length : 0;
|
||||
RsltItems_Disk_SingleWM = new string[count];
|
||||
for (int i = 0; i < count; i++) RsltItems_Disk_SingleWM[i] = ls.RsltItems_Disk_SingleWM[i];
|
||||
|
||||
count = (ls.RsltItems_Disk_CombinedWM != null) ? ls.RsltItems_Disk_CombinedWM.Length : 0;
|
||||
RsltItems_Disk_CombinedWM = new string[count];
|
||||
for (int i = 0; i < count; i++) RsltItems_Disk_CombinedWM[i] = ls.RsltItems_Disk_CombinedWM[i];
|
||||
|
||||
RsltsSingleClmnWdths = new int[ls.RsltsSingleClmnCount];
|
||||
for (int i = 0; i < RsltsSingleClmnCount; i++)
|
||||
RsltsSingleClmnWdths[i] = ls.RsltsSingleClmnWdths[i];
|
||||
RsltsCombinedClmnWdths = new int[ls.RsltsCombinedClmnCount];
|
||||
for (int i = 0; i < RsltsCombinedClmnCount; i++)
|
||||
RsltsCombinedClmnWdths[i] = ls.RsltsCombinedClmnWdths[i];
|
||||
}
|
||||
}
|
||||
|
||||
[XmlIgnore]
|
||||
public readonly bool AlwaysAskPasswdWhenUnlocking;
|
||||
|
||||
@ -274,20 +162,22 @@ namespace TBF
|
||||
/// <summary>
|
||||
/// Load public fields of this class from the XML file.
|
||||
/// </summary>
|
||||
public void Load()
|
||||
/// <returns>LocalSettings object or null when Load() fails</returns>
|
||||
public static LocalSettings Load(string fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (TextReader reader = new StreamReader(Program.LocalSettingsFileName))
|
||||
using (TextReader reader = new StreamReader(fileName))
|
||||
{
|
||||
LocalSettings ls = (new XmlSerializer(typeof(LocalSettings))).Deserialize(reader) as LocalSettings;
|
||||
// Copy the settings just in case De-serialize() completes OK
|
||||
this.Assign(ls);
|
||||
return ls;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string msg = e.Message;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -50,11 +50,10 @@ namespace TBF
|
||||
userNameTextBox.Text = Program.AdminUsername;
|
||||
passwordTextBox.Text = Program.AdminPassword;
|
||||
#endif
|
||||
int nrOfBenches = Program.LocalSettings.testBenches == null ? 0 : Program.LocalSettings.testBenches.GetLength(0);
|
||||
for (int i = 0; i < nrOfBenches; i++)
|
||||
for (int i = 0; i < Program.LocalSettings.BenchesCount; i++)
|
||||
{
|
||||
testBenchComboBox.Items.Add(Program.LocalSettings.testBenches[i].BenchName);
|
||||
if (benchName != null && benchName == Program.LocalSettings.testBenches[i].BenchName)
|
||||
testBenchComboBox.Items.Add(Program.LocalSettings.TestBenches[i].BenchName);
|
||||
if (benchName != null && benchName == Program.LocalSettings.TestBenches[i].BenchName)
|
||||
{
|
||||
testBenchComboBox.Text = benchName;
|
||||
}
|
||||
|
||||
@ -22,8 +22,9 @@ namespace TBF
|
||||
|
||||
public PreferencesDlg()
|
||||
{
|
||||
localSettings = new LocalSettings();
|
||||
localSettings.Assign(Program.LocalSettings);
|
||||
Program.LocalSettings.Save();
|
||||
localSettings = LocalSettings.Load(Program.LocalSettingsFileName);
|
||||
if (localSettings == null) throw new Exception("Cannot load local settings");
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
@ -47,7 +48,8 @@ namespace TBF
|
||||
/// <param name="e">Not used</param>
|
||||
private void okButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Program.LocalSettings.Assign(localSettings); // Update 'global' local settings
|
||||
localSettings.Save();
|
||||
Program.LocalSettings = LocalSettings.Load(Program.LocalSettingsFileName);
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
|
||||
|
||||
@ -23,8 +23,9 @@ namespace TBF
|
||||
const string log4netConfigFName = "log4netConfig.xml";
|
||||
|
||||
/// Local settings
|
||||
public static LocalSettings LocalSettings = new LocalSettings();
|
||||
public static LocalSettings LocalSettings;
|
||||
public const string LocalSettingsFileName = "config.xml";
|
||||
public const string LocalSettingsBackupName = "config.backup.xml";
|
||||
|
||||
/// Database related: This object reference is set after a successful user login
|
||||
public static DatabaseSettings CurrentBench;
|
||||
@ -65,6 +66,8 @@ namespace TBF
|
||||
{
|
||||
log.Fatal("--------------------------------------------------------------------------------");
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
|
||||
|
||||
/// Local program configuration directory including the trailing backslash
|
||||
string locAppDataDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) +
|
||||
Path.DirectorySeparatorChar + "TestBenchFramework" + Path.DirectorySeparatorChar;
|
||||
@ -103,9 +106,28 @@ namespace TBF
|
||||
log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(locAppDataDir + log4netConfigFName));
|
||||
log.Info("Entering application.");
|
||||
|
||||
///
|
||||
/// Load the local settings
|
||||
if (Program.LocalSettings == null) return; /// Fatal error
|
||||
LocalSettings.Load();
|
||||
///
|
||||
Program.LocalSettings = LocalSettings.Load(Program.LocalSettingsFileName);
|
||||
if (Program.LocalSettings == null || Program.LocalSettings.TestBenches == null)
|
||||
{
|
||||
/// Loading local seetings from regular config file failed. Use the backup
|
||||
Program.LocalSettings = LocalSettings.Load(Program.LocalSettingsBackupName);
|
||||
if (Program.LocalSettings == null || Program.LocalSettings.TestBenches == null)
|
||||
{
|
||||
return; /// Fatal error
|
||||
}
|
||||
else
|
||||
{
|
||||
LocalSettings.Save(); /// Save the settings to overwrite the wrong file
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Loading local seetings from the regular config file was successful. Update the backup
|
||||
File.Copy(Program.LocalSettingsFileName, Program.LocalSettingsBackupName, true);
|
||||
}
|
||||
|
||||
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(LocalSettings.Language);
|
||||
|
||||
@ -115,7 +137,7 @@ namespace TBF
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
/// Ensure that there is at least one bench in the configuration
|
||||
while (Program.LocalSettings.testBenches.GetLength(0) == 0)
|
||||
while (Program.LocalSettings.BenchesCount == 0)
|
||||
{
|
||||
log.Warn("No test benches in the local configuration -> display an appropriate dialog.");
|
||||
|
||||
@ -128,7 +150,8 @@ namespace TBF
|
||||
}
|
||||
|
||||
log.Warn("Loading the local settings again.");
|
||||
LocalSettings.Load();
|
||||
Program.LocalSettings = LocalSettings.Load(Program.LocalSettingsFileName);
|
||||
if (Program.LocalSettings == null) return; /// Fatal error
|
||||
}
|
||||
|
||||
/// User login
|
||||
@ -214,7 +237,8 @@ namespace TBF
|
||||
{
|
||||
return; /// Exit program
|
||||
}
|
||||
LocalSettings.Load();
|
||||
Program.LocalSettings = LocalSettings.Load(Program.LocalSettingsFileName);
|
||||
if (Program.LocalSettings == null) return; /// Fatal error
|
||||
break; /// Retry the loop
|
||||
}
|
||||
}
|
||||
@ -241,20 +265,46 @@ namespace TBF
|
||||
}
|
||||
}
|
||||
|
||||
/// Open the main application window
|
||||
log.Info("Creating the main window");
|
||||
MainWnd = new MainWnd();
|
||||
log.Info("Opening the main window");
|
||||
Application.Run(MainWnd);
|
||||
|
||||
/// Save local settings
|
||||
log.Info("The main window was closed, saving the local parameters");
|
||||
LocalSettings.Save();
|
||||
try
|
||||
{
|
||||
/// Open the main application window
|
||||
log.Info("Creating the main window");
|
||||
MainWnd = new MainWnd();
|
||||
log.Info("Opening the main window");
|
||||
Application.Run(MainWnd);
|
||||
log.Info("The main window was closed");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogException(log, "Exception in Application.Run(MainWnd)", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
/// Save local settings
|
||||
LocalSettings.Save();
|
||||
}
|
||||
|
||||
/// Close Fluent NHibernate
|
||||
/// Todo
|
||||
|
||||
log.Info("Exiting application.");
|
||||
}
|
||||
}
|
||||
|
||||
static void MyHandler(object sender, UnhandledExceptionEventArgs args)
|
||||
{
|
||||
LogException(log, "Unhandled exception", (Exception)args.ExceptionObject);
|
||||
}
|
||||
|
||||
static void LogException(ILog log, string description, Exception e)
|
||||
{
|
||||
log.FatalFormat("---------------( {0} )---------------", description);
|
||||
log.FatalFormat("Message : {0}", e.Message);
|
||||
if (e.InnerException != null)
|
||||
{
|
||||
log.FatalFormat("InnerMessage : {0}", e.InnerException.Message);
|
||||
}
|
||||
log.FatalFormat("StackTrace : {0}{1}", Environment.NewLine, e.StackTrace);
|
||||
log.Fatal("--------------------------------------");
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user