iPerlCommunication : Sequence conditions
This commit is contained in:
parent
b044b00571
commit
a7118935ca
@ -1,5 +1,5 @@
|
||||
///
|
||||
/// Copyright (c) 2015 Sensus Metering Systems
|
||||
/// Copyright (c) 2015 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
|
||||
|
||||
@ -25,27 +25,27 @@ namespace TBF.Rig.Sequences
|
||||
|
||||
|
||||
int simultWithPurgingCount;
|
||||
Generic.IComponentCfg simultWithPurgingCfg;
|
||||
Generic.IComponent simultWithPurging;
|
||||
Generic.IProcedureParams simultWithPurgingProcParams;
|
||||
IList<Config.Entities.Test> simultWithPurgingTests;
|
||||
IList<Generic.ITestParams> simultWithPurgingTestParams;
|
||||
|
||||
int simultWithEvacuationCount;
|
||||
Generic.IComponentCfg simultWithEvacuationCfg;
|
||||
Generic.IComponent simultWithEvacuation;
|
||||
Generic.IProcedureParams simultWithEvacuationProcParams;
|
||||
IList<Config.Entities.Test> simultWithEvacuationTests;
|
||||
IList<Generic.ITestParams> simultWithEvacuationTestParams;
|
||||
|
||||
System.Windows.Forms.Form modelessDlg;
|
||||
///
|
||||
delegate void CommunicationFormDlgt(MainSeq myRef, Generic.IComponentCfg cfg, Generic.IProcedureParams procParams, IList<Test> tests, IList<Generic.ITestParams> multiTestParams);
|
||||
delegate void CommunicationFormDlgt(MainSeq myRef, Generic.IComponent comp, Generic.IProcedureParams procParams, IList<Test> tests, IList<Generic.ITestParams> multiTestParams);
|
||||
///
|
||||
void OpenIPerlCommForm(MainSeq myRef, Generic.IComponentCfg cfg, Generic.IProcedureParams procParams, IList<Test> tests, IList<Generic.ITestParams> multiTestParams)
|
||||
void OpenIPerlCommForm(MainSeq myRef, Generic.IComponent testMethod, Generic.IProcedureParams procParams, IList<Test> tests, IList<Generic.ITestParams> multiTestParams)
|
||||
{
|
||||
try
|
||||
{
|
||||
/// 1nd argument
|
||||
TestMethods.iPerlCommunication.TestMethodCfg iPerlCfg = cfg as TestMethods.iPerlCommunication.TestMethodCfg;
|
||||
TestMethods.iPerlCommunication.TestMethodCfg iPerlCfg = testMethod.Cfg as TestMethods.iPerlCommunication.TestMethodCfg;
|
||||
|
||||
/// 2rd argument: as is
|
||||
|
||||
@ -53,7 +53,8 @@ namespace TBF.Rig.Sequences
|
||||
IList<TestMethods.iPerlCommunication.iPerlCommunicationParams> iPerlCommParams = new List<TestMethods.iPerlCommunication.iPerlCommunicationParams>();
|
||||
foreach (var tp in multiTestParams) iPerlCommParams.Add(tp as TestMethods.iPerlCommunication.iPerlCommunicationParams);
|
||||
|
||||
myRef.modelessDlg = new TestMethods.iPerlCommunication.iPerlCommunicationForm(iPerlCfg, tests, iPerlCommParams);
|
||||
myRef.modelessDlg = new TestMethods.iPerlCommunication.iPerlCommunicationForm(
|
||||
testMethod as TBF.Rig.TestMethods.iPerlCommunication.TestMethod, tests, iPerlCommParams);
|
||||
myRef.modelessDlg.Show();
|
||||
}
|
||||
catch (Exception e)
|
||||
@ -69,21 +70,21 @@ namespace TBF.Rig.Sequences
|
||||
}
|
||||
}
|
||||
///
|
||||
void OpenS640CommForm(MainSeq myRef, Generic.IComponentCfg cfg, Generic.IProcedureParams procParams, IList<Test> tests, IList<Generic.ITestParams> multiTestParams)
|
||||
void OpenS640CommForm(MainSeq myRef, Generic.IComponent testMethod, Generic.IProcedureParams procParams, IList<Test> tests, IList<Generic.ITestParams> multiTestParams)
|
||||
{
|
||||
try
|
||||
{
|
||||
TestMethods.S640Communication.S640Activity activity; /// 1st argument
|
||||
TBF.Rig.TestMethods.S640Communication.I640Cfg config; /// 2nd argument
|
||||
if (cfg is TestMethods.S640Communication.S640StartCfg)
|
||||
if (testMethod.Cfg is TestMethods.S640Communication.S640StartCfg)
|
||||
{
|
||||
activity = TestMethods.S640Communication.S640Activity.Start;
|
||||
config = (cfg as TestMethods.S640Communication.S640StartCfg);
|
||||
config = (testMethod.Cfg as TestMethods.S640Communication.S640StartCfg);
|
||||
}
|
||||
else if (cfg is TestMethods.S640Communication.S640EndCfg)
|
||||
else if (testMethod.Cfg is TestMethods.S640Communication.S640EndCfg)
|
||||
{
|
||||
activity = TestMethods.S640Communication.S640Activity.End;
|
||||
config = (cfg as TestMethods.S640Communication.S640EndCfg);
|
||||
config = (testMethod.Cfg as TestMethods.S640Communication.S640EndCfg);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -131,13 +132,13 @@ namespace TBF.Rig.Sequences
|
||||
FillState = FillState.Unknown;
|
||||
|
||||
simultWithPurgingCount = 0;
|
||||
simultWithPurgingCfg = null;
|
||||
simultWithPurging = null;
|
||||
simultWithPurgingProcParams = null;
|
||||
simultWithPurgingTests = new List<Config.Entities.Test>();
|
||||
simultWithPurgingTestParams = new List<Generic.ITestParams>();
|
||||
|
||||
simultWithEvacuationCount = 0;
|
||||
simultWithEvacuationCfg = null;
|
||||
simultWithEvacuation = null;
|
||||
simultWithEvacuationProcParams = null;
|
||||
simultWithEvacuationTests = new List<Config.Entities.Test>();
|
||||
simultWithEvacuationTestParams = new List<Generic.ITestParams>();
|
||||
@ -588,11 +589,11 @@ namespace TBF.Rig.Sequences
|
||||
var firstRR = ProcessData.RegisterReaders.FirstOrDefault<IRegReader>(x => x != null);
|
||||
if (firstRR is TBF.Rig.TestMethods.iPerlCommunication.iPerlHead.IperlHead)
|
||||
{
|
||||
Program.MainWnd.Invoke(new CommunicationFormDlgt(OpenIPerlCommForm), new object[] { this, simultWithPurgingCfg, simultWithPurgingProcParams, simultWithPurgingTests, simultWithPurgingTestParams });
|
||||
Program.MainWnd.Invoke(new CommunicationFormDlgt(OpenIPerlCommForm), new object[] { this, simultWithPurging, simultWithPurgingProcParams, simultWithPurgingTests, simultWithPurgingTestParams });
|
||||
}
|
||||
else if (firstRR is TBF.Rig.RegisterReaders.S640Stream.S640Stream)
|
||||
{
|
||||
Program.MainWnd.Invoke(new CommunicationFormDlgt(OpenS640CommForm), new object[] { this, simultWithPurgingCfg, simultWithPurgingProcParams, simultWithPurgingTests, simultWithPurgingTestParams });
|
||||
Program.MainWnd.Invoke(new CommunicationFormDlgt(OpenS640CommForm), new object[] { this, simultWithPurging, simultWithPurgingProcParams, simultWithPurgingTests, simultWithPurgingTestParams });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -696,7 +696,7 @@ namespace TBF.Rig.Sequences
|
||||
/// Collect steps (e.g. iPerl communication) to be done simultaneously with purging
|
||||
///
|
||||
simultWithPurgingCount = 0;
|
||||
simultWithPurgingCfg = null;
|
||||
simultWithPurging = null;
|
||||
simultWithPurgingProcParams = null;
|
||||
simultWithPurgingTests.Clear();
|
||||
simultWithPurgingTestParams.Clear();
|
||||
@ -715,10 +715,10 @@ namespace TBF.Rig.Sequences
|
||||
|
||||
if (simultWithPurgingCount == 0)
|
||||
{
|
||||
simultWithPurgingCfg = simultTest.Cfg;
|
||||
simultWithPurgingProcParams = simultWithPurgingCfg.GetRuntimeProcParamsProvider() as Generic.IProcedureParams;
|
||||
simultWithPurging = simultTest;
|
||||
simultWithPurgingProcParams = simultWithPurging.Cfg.GetRuntimeProcParamsProvider() as Generic.IProcedureParams;
|
||||
}
|
||||
else if (simultTest.Cfg != simultWithPurgingCfg)
|
||||
else if (simultTest != simultWithPurging)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -739,7 +739,7 @@ namespace TBF.Rig.Sequences
|
||||
/// Collect steps (e.g. iPerl communication) to be done simultaneously with evacuation
|
||||
///
|
||||
simultWithEvacuationCount = 0;
|
||||
simultWithEvacuationCfg = null;
|
||||
simultWithEvacuation = null;
|
||||
simultWithEvacuationProcParams = null;
|
||||
simultWithEvacuationTests.Clear();
|
||||
simultWithEvacuationTestParams.Clear();
|
||||
@ -760,10 +760,10 @@ namespace TBF.Rig.Sequences
|
||||
|
||||
if (simultWithEvacuationCount == 0)
|
||||
{
|
||||
simultWithEvacuationCfg = simultTest.Cfg;
|
||||
simultWithEvacuationProcParams = simultWithEvacuationCfg.GetRuntimeProcParamsProvider() as Generic.IProcedureParams;
|
||||
simultWithEvacuation = simultTest;
|
||||
simultWithEvacuationProcParams = simultWithEvacuation.Cfg.GetRuntimeProcParamsProvider() as Generic.IProcedureParams;
|
||||
}
|
||||
else if (simultTest.Cfg != simultWithEvacuationCfg)
|
||||
else if (simultTest != simultWithEvacuation)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -801,12 +801,12 @@ namespace TBF.Rig.Sequences
|
||||
if (firstRR is TBF.Rig.TestMethods.iPerlCommunication.iPerlHead.IperlHead)
|
||||
{
|
||||
Program.MainWnd.Invoke(new CommunicationFormDlgt(OpenIPerlCommForm),
|
||||
new object[] { this, simultWithEvacuationCfg, simultWithEvacuationProcParams, simultWithEvacuationTests, simultWithEvacuationTestParams });
|
||||
new object[] { this, simultWithEvacuation, simultWithEvacuationProcParams, simultWithEvacuationTests, simultWithEvacuationTestParams });
|
||||
}
|
||||
else if (firstRR is TBF.Rig.RegisterReaders.S640Stream.S640Stream)
|
||||
{
|
||||
Program.MainWnd.Invoke(new CommunicationFormDlgt(OpenS640CommForm),
|
||||
new object[] { this, simultWithEvacuationCfg, simultWithEvacuationProcParams, simultWithEvacuationTests, simultWithEvacuationTestParams });
|
||||
new object[] { this, simultWithEvacuation, simultWithEvacuationProcParams, simultWithEvacuationTests, simultWithEvacuationTestParams });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
///
|
||||
/// Copyright (c) 2022 Sensus Slovensko a.s.
|
||||
///
|
||||
using TBF.Resources;
|
||||
|
||||
namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
{
|
||||
public enum ConditionID
|
||||
{
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
Count,
|
||||
}
|
||||
|
||||
public class SequenceConditionOp : IOperation
|
||||
{
|
||||
public const string ConditionNameFmt = "iPERL communication milestone {0}";
|
||||
|
||||
ConditionID id;
|
||||
TestMethod testMethodComponent;
|
||||
|
||||
public SequenceConditionOp(TestMethod testMethodComponent, ConditionID id)
|
||||
{
|
||||
this.testMethodComponent = testMethodComponent;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void Start() { }
|
||||
|
||||
public Event Run()
|
||||
{
|
||||
bool conditionMet = testMethodComponent.IperlCommMilestone[(int)id];
|
||||
return conditionMet ? Event.ConditionMet : Event.ConditionNotMet;
|
||||
}
|
||||
|
||||
public void Stop() { }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(ConditionNameFmt, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,17 +1,18 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2021 Sensus Slovensko a.s.
|
||||
/// Copyright (c) 2015-2022 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using log4net;
|
||||
using Common;
|
||||
using Config.Entities;
|
||||
using TBF.Rig.GenericDevices;
|
||||
using TBF.Rig.Sequences;
|
||||
using TBF.UiBridge;
|
||||
|
||||
namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
{
|
||||
public class TestMethod : ComponentBase, GenericDevices.ISimultTestMethod
|
||||
public class TestMethod : ComponentBase, ISimultTestMethod, ISequenceCondition
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(TestMethod));
|
||||
protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData");
|
||||
@ -60,14 +61,32 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
|
||||
|
||||
readonly TestMethodCfg testMethodCfg;
|
||||
|
||||
public bool[] IperlCommMilestone;
|
||||
IList<IOperation> sequenceConditionOps;
|
||||
|
||||
public TestMethod() { }
|
||||
public TestMethod()
|
||||
{
|
||||
CreateMilestonesAndConditions();
|
||||
}
|
||||
|
||||
public TestMethod(Generic.IComponentCfg cfg)
|
||||
: base(cfg)
|
||||
{
|
||||
testMethodCfg = cfg as TestMethodCfg;
|
||||
}
|
||||
CreateMilestonesAndConditions();
|
||||
}
|
||||
|
||||
void CreateMilestonesAndConditions()
|
||||
{
|
||||
IperlCommMilestone = new bool[(int)ConditionID.Count];
|
||||
|
||||
sequenceConditionOps = new List<IOperation>();
|
||||
for (ConditionID id = ConditionID.A; id < ConditionID.Count; id++)
|
||||
{
|
||||
sequenceConditionOps.Add(new SequenceConditionOp(this, id));
|
||||
}
|
||||
}
|
||||
|
||||
/// IDevice interface - only Initialize() is used
|
||||
public override void Initialize()
|
||||
@ -89,7 +108,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
{
|
||||
if (DebugLevel == DebugMode.Normal)
|
||||
{
|
||||
return (new iPerlCommunicationSeq()).Execute(test, repetNr, testMethodCfg, testMethodCfg.TestParams);
|
||||
return (new iPerlCommunicationSeq()).Execute(test, repetNr, this, testMethodCfg.TestParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -100,5 +119,18 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
return new List<Event> { Event.Done };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int ConditionsCount { get { return (int)ConditionID.Count; } }
|
||||
|
||||
public string ConditionName(int i)
|
||||
{
|
||||
return (i >= 0 && i < (int)ConditionID.Count) ? ConditionOp(i).ToString() : string.Empty;
|
||||
}
|
||||
|
||||
public IOperation ConditionOp(int i)
|
||||
{
|
||||
return (i >= 0 && i < (int)ConditionID.Count) ? sequenceConditionOps[i] : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -701,6 +701,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
///
|
||||
/// RFID multiplexer PCB / RFID serial port and worker thread related variables
|
||||
///
|
||||
static TestMethod testMethod;
|
||||
static TestMethodCfg cfg;
|
||||
static IList<Config.Entities.Test> tests;
|
||||
static IList<iPerlCommunicationParams> multiTestParams;
|
||||
@ -742,8 +743,8 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
/// Constructor for one iPerlCommunication 'test'
|
||||
/// </summary>
|
||||
/// <param name="waterMetersCount">Number of text boxes for serial numbers</param>
|
||||
public iPerlCommunicationForm(TestMethodCfg cfg, Test test, iPerlCommunicationParams testParams)
|
||||
: this(cfg, new List<Test> { test }, new List<iPerlCommunicationParams> { testParams })
|
||||
public iPerlCommunicationForm(TestMethod testMethod, Test test, iPerlCommunicationParams testParams)
|
||||
: this(testMethod, new List<Test> { test }, new List<iPerlCommunicationParams> { testParams })
|
||||
{
|
||||
}
|
||||
|
||||
@ -751,12 +752,13 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
/// Constructor for multiple iPerlCommunication 'tests'
|
||||
/// </summary>
|
||||
/// <param name="waterMetersCount">Number of text boxes for serial numbers</param>
|
||||
public iPerlCommunicationForm(TestMethodCfg cfg, IList<Test> tests, IList<iPerlCommunicationParams> multiTestParams)
|
||||
public iPerlCommunicationForm(TestMethod testMethod, IList<Test> tests, IList<iPerlCommunicationParams> multiTestParams)
|
||||
: this()
|
||||
{
|
||||
checkBoxesEditMode = false;
|
||||
|
||||
iPerlCommunicationForm.cfg = cfg;
|
||||
iPerlCommunicationForm.testMethod = testMethod;
|
||||
iPerlCommunicationForm.cfg = testMethod.Cfg as TestMethodCfg;
|
||||
iPerlCommunicationForm.tests = tests;
|
||||
iPerlCommunicationForm.multiTestParams = multiTestParams;
|
||||
|
||||
@ -1238,7 +1240,21 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
else
|
||||
{
|
||||
error = CommErr.None;
|
||||
resultStr = "Invalid activity";
|
||||
|
||||
ConditionID id;
|
||||
for (id = ConditionID.A; id < ConditionID.Count; id++)
|
||||
{
|
||||
if (currentActivity.ToLower() == string.Format(SequenceConditionOp.ConditionNameFmt, id).ToLower())
|
||||
{
|
||||
error = SetIperlCommMilestoneReached(testMethod, id, ref resultStr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (id == ConditionID.Count)
|
||||
{
|
||||
resultStr = "Invalid activity"; /// No activity or milestone
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
@ -3200,6 +3216,19 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
return CommErr.None;
|
||||
}
|
||||
|
||||
static CommErr SetIperlCommMilestoneReached(TestMethod testMethod, ConditionID id, ref string resultStr)
|
||||
{
|
||||
if (id < ConditionID.A || id >= ConditionID.Count)
|
||||
{
|
||||
resultStr = Strings.Error;
|
||||
return CommErr.WrongArguments;
|
||||
}
|
||||
|
||||
testMethod.IperlCommMilestone[(int)id] = true;
|
||||
resultStr = string.Format(SequenceConditionOp.ConditionNameFmt, id);
|
||||
return CommErr.None;
|
||||
}
|
||||
|
||||
#endif /// IPERL
|
||||
|
||||
#endregion
|
||||
|
||||
@ -91,6 +91,11 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
retVal.Add(string.Format("{0} if enabled", iPerlCommunicationForm.ReadConfigurationStr));
|
||||
retVal.Add(string.Format("{0} 80", iPerlCommunicationForm.SetTestModeStr));
|
||||
retVal.Add("iPerl_check prevWorkStep direction q2factors");
|
||||
for (ConditionID id = ConditionID.A; id < ConditionID.Count; id++)
|
||||
{
|
||||
retVal.Add(string.Format(SequenceConditionOp.ConditionNameFmt, id));
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
else
|
||||
|
||||
@ -26,11 +26,11 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
|
||||
System.Windows.Forms.Form modelessDlg;
|
||||
///
|
||||
delegate void iPerlCommFormDlgt(iPerlCommunicationSeq myRef, TestMethodCfg cfg, Test test, iPerlCommunicationParams testParams);
|
||||
delegate void iPerlCommFormDlgt(iPerlCommunicationSeq myRef, TestMethod method, Test test, iPerlCommunicationParams testParams);
|
||||
///
|
||||
void OpenIPerlCommForm(iPerlCommunicationSeq myRef, TestMethodCfg cfg, Test test, iPerlCommunicationParams testParams)
|
||||
void OpenIPerlCommForm(iPerlCommunicationSeq myRef, TestMethod method, Test test, iPerlCommunicationParams testParams)
|
||||
{
|
||||
myRef.modelessDlg = new iPerlCommunicationForm(cfg, test, testParams);
|
||||
myRef.modelessDlg = new iPerlCommunicationForm(method, test, testParams);
|
||||
myRef.modelessDlg.Show();
|
||||
}
|
||||
|
||||
@ -52,8 +52,10 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
/// Event.OpArgumentError . Target flow is out of range
|
||||
/// Event.Error . . . . . . Unspecified error
|
||||
/// </returns>
|
||||
public IList<Event> Execute(Test test, int repetitionNr, TestMethodCfg cfg, iPerlCommunicationParams testParams)
|
||||
public IList<Event> Execute(Test test, int repetitionNr, TestMethod method, iPerlCommunicationParams testParams)
|
||||
{
|
||||
TestMethodCfg cfg = method.Cfg as TestMethodCfg;
|
||||
|
||||
IList<Event> e; /// Events from currently running operations
|
||||
checkUiOp = new Operations.CheckUIOp(true); /// Runs in more then one state
|
||||
modelessDlg = null;
|
||||
@ -322,7 +324,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
///
|
||||
/// Show the modeless dialog with error indication
|
||||
///
|
||||
Program.MainWnd.Invoke(new iPerlCommFormDlgt(OpenIPerlCommForm), new object[] { this, cfg, test, testParams });
|
||||
Program.MainWnd.Invoke(new iPerlCommFormDlgt(OpenIPerlCommForm), new object[] { this, method, test, testParams });
|
||||
|
||||
//------------------------------------------------
|
||||
Bridge.OnActivity(this, Strings.iPerl_Communication_in_progress);
|
||||
|
||||
@ -1611,6 +1611,7 @@
|
||||
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlHead\OptoReceivedEventArgs.cs" />
|
||||
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlHead\ProcParams.cs" />
|
||||
<Compile Include="Rig\TestMethods\iPerlCommunication\iPerlHead\StatusStruct.cs" />
|
||||
<Compile Include="Rig\TestMethods\iPerlCommunication\SequenceConditionOp.cs" />
|
||||
<Compile Include="Rig\TestMethods\iPerlCommunication\TestMethod.cs" />
|
||||
<Compile Include="Rig\TestMethods\iPerlCommunication\TestMethodCfg.cs" />
|
||||
<Compile Include="Rig\TestMethods\iPerlCommunication\TestMethodCfgCtrl.cs">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user