|
|
|
@@ -114,40 +114,11 @@ namespace IOB_WIN
|
|
|
|
|
/// Contatore x invio dati
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int counter { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Ultimo URL
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string lastUrl { get; set; }
|
|
|
|
|
|
|
|
|
|
// Tolgo gestione strobes --> bitarray!
|
|
|
|
|
#if false
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 16 byte di strobe (4 word da 32 bit di flags...)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public byte[] Strobes = new byte[16];
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 16 byte di strobe - valori PREVIOUS (lettura precedente)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public byte[] StrobesPrev = new byte[16];
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Prima word di strobe da array flag completo
|
|
|
|
|
/// </summary>
|
|
|
|
|
public StFlag32 STRB_DW0
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return (StFlag32)BitConverter.ToUInt32(Strobes, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Prima word di strobe (valori PRECEDENTI) da array flag completo
|
|
|
|
|
/// </summary>
|
|
|
|
|
public StFlag32 STRB_00_PREV
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return (StFlag32)BitConverter.ToUInt32(StrobesPrev, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Array dei contatori x segnali blinking
|
|
|
|
|
/// </summary>
|
|
|
|
@@ -265,63 +236,6 @@ namespace IOB_WIN
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void loadPersData()
|
|
|
|
|
{
|
|
|
|
|
#if false
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// nuova lettura valori da file persistenza...
|
|
|
|
|
contOreMaccOn = getStoredValDouble("ACC_TIME");
|
|
|
|
|
contOreMaccLav = getStoredValDouble("ACC_TIME_WORK");
|
|
|
|
|
contSlittaTast = getStoredValDouble("SlittaTastatore_Count");
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < currAdpConf.nUnOp; i++)
|
|
|
|
|
{
|
|
|
|
|
contGiriElettrom[i] = getStoredValUInt(string.Format("UnOp_{0:00}_AccTime", i + 1));
|
|
|
|
|
currNumCambiUt[i] = getStoredValUInt(string.Format("UnOp_{0:00}_NumCU", i + 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < currAdpConf.nAxis; i++)
|
|
|
|
|
{
|
|
|
|
|
contDistMovAssi[i] = getStoredValUInt(string.Format("Axis_{0:00}_DistDone", i + 1));
|
|
|
|
|
contNumInvAssi[i] = getStoredValUInt(string.Format("Axis_{0:00}_InvDDone", i + 1));
|
|
|
|
|
contAccTimeAssi[i] = getStoredValDouble(string.Format("Axis_{0:00}_AccTime", i + 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < currAdpConf.nVacuumPump; i++)
|
|
|
|
|
{
|
|
|
|
|
currVacPumpWrkTime[i] = getStoredValUInt(string.Format("VacPump_{0:00}_WrkTime", i + 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < currAdpConf.nVacuumAct; i++)
|
|
|
|
|
{
|
|
|
|
|
currVacActCount[i] = getStoredValUInt(string.Format("VacAct_{0:00}_Count", i + 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < currAdpConf.nLubro; i++)
|
|
|
|
|
{
|
|
|
|
|
currLubroCount[i] = getStoredValUInt(string.Format("Lubro_{0:00}_Count", i + 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < currAdpConf.nSlittaMag; i++)
|
|
|
|
|
{
|
|
|
|
|
currSlittaMag[i] = getStoredValUInt(string.Format("SlittaMagazzino_{0:00}_Count", i + 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < mCounters.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
currCounters[i] = getStoredValUInt(string.Format("Counter_{0:000}", i + 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < currAdpConf.nProtMag; i++)
|
|
|
|
|
{
|
|
|
|
|
currProtMag[i] = getStoredValUInt(string.Format("ProtMagazzino_{0:00}_Count", i + 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
catch (Exception exc)
|
|
|
|
|
{
|
|
|
|
|
lg.Error(string.Format("Eccezione in decodifica valori PersLayer: {0}{1}", Environment.NewLine, exc));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@@ -337,169 +251,6 @@ namespace IOB_WIN
|
|
|
|
|
TimingData.resetData();
|
|
|
|
|
// aggiungo altri defaults
|
|
|
|
|
setDefaults();
|
|
|
|
|
#if false
|
|
|
|
|
// inizializzo vettori di utility..
|
|
|
|
|
loadAllarmi();
|
|
|
|
|
loadSubMode();
|
|
|
|
|
loadOtherFile();
|
|
|
|
|
|
|
|
|
|
// salvo porta!
|
|
|
|
|
mAdapter.Port = port;
|
|
|
|
|
adpPortNum = port;
|
|
|
|
|
// avvio!
|
|
|
|
|
mAdapter.Start();
|
|
|
|
|
|
|
|
|
|
// setto status a ON
|
|
|
|
|
mStatus.Value = "ON";
|
|
|
|
|
|
|
|
|
|
// resetto running flag...
|
|
|
|
|
adpCommAct = false;
|
|
|
|
|
|
|
|
|
|
// avvio i sample vectors...
|
|
|
|
|
istOreMaccOn = new sampleVect();
|
|
|
|
|
istOreMaccLav = new sampleVect();
|
|
|
|
|
istSlittaTast = new sampleVect();
|
|
|
|
|
|
|
|
|
|
// carico valori da adapter x i conteggi
|
|
|
|
|
contOreMaccOn = currAdpConf.ContOreMaccOn;
|
|
|
|
|
contOreMaccLav = currAdpConf.ContOreMaccLav;
|
|
|
|
|
contSlittaTast = currAdpConf.ContSlittaTast;
|
|
|
|
|
contGiriElettrom = new uint[currAdpConf.nUnOp];
|
|
|
|
|
istGiriElettrom = new sampleVect[currAdpConf.nUnOp];
|
|
|
|
|
currNumCambiUt = new uint[currAdpConf.nUnOp];
|
|
|
|
|
istNumCambiUt = new sampleVect[currAdpConf.nUnOp];
|
|
|
|
|
for (int i = 0; i < currAdpConf.nUnOp; i++)
|
|
|
|
|
{
|
|
|
|
|
// leggo tutti i dati...
|
|
|
|
|
List<DataRefItem<string, string>> listaDR = currAdpConf.UnOp[i].dataRefList;
|
|
|
|
|
// punto all'item
|
|
|
|
|
DataRefItem<string, string> riContRpm = listaDR.Find(x => x.Key == string.Format("UnOp_{0:00}_AccTime", i + 1));
|
|
|
|
|
DataRefItem<string, string> riContNumCU = listaDR.Find(x => x.Key == string.Format("UnOp_{0:00}_NumCU", i + 1));
|
|
|
|
|
// recupero valore giri...
|
|
|
|
|
UInt32 contTotGiri = Convert.ToUInt32(riContRpm.Value);
|
|
|
|
|
// recupero valore num cambi ut...
|
|
|
|
|
UInt32 contNumCU = Convert.ToUInt32(riContNumCU.Value);
|
|
|
|
|
// salvo valore letto
|
|
|
|
|
contGiriElettrom[i] = contTotGiri;
|
|
|
|
|
currNumCambiUt[i] = contNumCU;
|
|
|
|
|
istGiriElettrom[i] = new sampleVect();
|
|
|
|
|
istNumCambiUt[i] = new sampleVect();
|
|
|
|
|
}
|
|
|
|
|
// imposto num assi e leggo valori salvati...
|
|
|
|
|
contDistMovAssi = new double[currAdpConf.nAxis];
|
|
|
|
|
istDistMovAssi = new sampleVect[currAdpConf.nAxis];
|
|
|
|
|
istLoadAssi = new sampleVect[currAdpConf.nAxis];
|
|
|
|
|
contNumInvAssi = new uint[currAdpConf.nAxis];
|
|
|
|
|
istAccTimeAssi = new sampleVect[currAdpConf.nAxis];
|
|
|
|
|
contAccTimeAssi = new double[currAdpConf.nAxis];
|
|
|
|
|
istNumInvAssi = new sampleVect[currAdpConf.nAxis];
|
|
|
|
|
lastChekAccumTimeAxis = DateTime.Now;
|
|
|
|
|
for (int i = 0; i < currAdpConf.nAxis; i++)
|
|
|
|
|
{
|
|
|
|
|
// leggo tutti i dati...
|
|
|
|
|
List<DataRefItem<string, string>> listaDR = currAdpConf.Axis[i].dataRefList;
|
|
|
|
|
// punto all'item
|
|
|
|
|
DataRefItem<string, string> riContDist = listaDR.Find(x => x.Key == string.Format("Axis_{0:00}_DistDone", i + 1));
|
|
|
|
|
DataRefItem<string, string> riNumInv = listaDR.Find(x => x.Key == string.Format("Axis_{0:00}_Invers", i + 1));
|
|
|
|
|
DataRefItem<string, string> riAccTime = listaDR.Find(x => x.Key == string.Format("Axis_{0:00}_AccTime", i + 1));
|
|
|
|
|
// recupero valori...
|
|
|
|
|
contDistMovAssi[i] = Convert.ToUInt32(riContDist.Value);
|
|
|
|
|
contNumInvAssi[i] = Convert.ToUInt32(riNumInv.Value);
|
|
|
|
|
contAccTimeAssi[i] = Convert.ToDouble(riAccTime.Value);
|
|
|
|
|
vettAxis[i].mAxAlarmCNC.Normal();
|
|
|
|
|
vettAxis[i].mAxAlarmPLC.Normal();
|
|
|
|
|
istDistMovAssi[i] = new sampleVect();
|
|
|
|
|
istLoadAssi[i] = new sampleVect();
|
|
|
|
|
istAccTimeAssi[i] = new sampleVect();
|
|
|
|
|
istNumInvAssi[i] = new sampleVect();
|
|
|
|
|
}
|
|
|
|
|
currPathPartId = new string[currAdpConf.nPath];
|
|
|
|
|
istPathPartId = new string[currAdpConf.nPath];
|
|
|
|
|
currPathProgrName = new string[currAdpConf.nPath];
|
|
|
|
|
istPathProgrName = new string[currAdpConf.nPath];
|
|
|
|
|
currPathPartCount = new uint[currAdpConf.nPath];
|
|
|
|
|
istPathPartCount = new sampleVect[currAdpConf.nPath];
|
|
|
|
|
for (int i = 0; i < currAdpConf.nPath; i++)
|
|
|
|
|
{
|
|
|
|
|
// leggo tutti i dati...
|
|
|
|
|
List<DataRefItem<string, string>> listaDR = currAdpConf.Path[i].dataRefList;
|
|
|
|
|
// punto all'item
|
|
|
|
|
DataRefItem<string, string> riPathProgr = listaDR.Find(x => x.Key == string.Format("Path_{0:00}_PartId", i + 1));
|
|
|
|
|
DataRefItem<string, string> riPathPzTot = listaDR.Find(x => x.Key == string.Format("Path_{0:00}_PZ_TOT", i + 1));
|
|
|
|
|
// recupero valori...
|
|
|
|
|
currPathPartId[i] = riPathProgr.Value;
|
|
|
|
|
currPathPartCount[i] = Convert.ToUInt32(riPathPzTot.Value);
|
|
|
|
|
currPathProgrName[i] = "";
|
|
|
|
|
vettPath[i].mPathAlarmCNC.Normal();
|
|
|
|
|
vettPath[i].mPathAlarmPLC.Normal();
|
|
|
|
|
istPathPartCount[i] = new sampleVect();
|
|
|
|
|
}
|
|
|
|
|
currVacPumpWrkTime = new uint[currAdpConf.nVacuumPump];
|
|
|
|
|
istVacPumpWrkTime = new sampleVect[currAdpConf.nVacuumPump];
|
|
|
|
|
for (int i = 0; i < currAdpConf.nVacuumPump; i++)
|
|
|
|
|
{
|
|
|
|
|
// leggo tutti i dati...
|
|
|
|
|
List<DataRefItem<string, string>> listaDR = currAdpConf.VacuumPump[i].dataRefList;
|
|
|
|
|
// punto all'item
|
|
|
|
|
DataRefItem<string, string> riVacPumpWrk = listaDR.Find(x => x.Key == string.Format("VacPump_{0:00}_WrkTime", i + 1));
|
|
|
|
|
// recupero valori...
|
|
|
|
|
currVacPumpWrkTime[i] = Convert.ToUInt32(riVacPumpWrk.Value);
|
|
|
|
|
istVacPumpWrkTime[i] = new sampleVect();
|
|
|
|
|
}
|
|
|
|
|
currVacActCount = new uint[currAdpConf.nVacuumAct];
|
|
|
|
|
istVacActCount = new sampleVect[currAdpConf.nVacuumAct];
|
|
|
|
|
for (int i = 0; i < currAdpConf.nVacuumAct; i++)
|
|
|
|
|
{
|
|
|
|
|
// leggo tutti i dati...
|
|
|
|
|
List<DataRefItem<string, string>> listaDR = currAdpConf.VacuumAct[i].dataRefList;
|
|
|
|
|
// punto all'item
|
|
|
|
|
DataRefItem<string, string> riVacActCount = listaDR.Find(x => x.Key == string.Format("VacAct_{0:00}_Count", i + 1));
|
|
|
|
|
// recupero valori...
|
|
|
|
|
currVacActCount[i] = Convert.ToUInt32(riVacActCount.Value);
|
|
|
|
|
istVacActCount[i] = new sampleVect();
|
|
|
|
|
}
|
|
|
|
|
currLubroCount = new uint[currAdpConf.nLubro];
|
|
|
|
|
istLubroCount = new sampleVect[currAdpConf.nLubro];
|
|
|
|
|
for (int i = 0; i < currAdpConf.nLubro; i++)
|
|
|
|
|
{
|
|
|
|
|
// leggo tutti i dati...
|
|
|
|
|
List<DataRefItem<string, string>> listaDR = currAdpConf.Lubro[i].dataRefList;
|
|
|
|
|
// punto all'item
|
|
|
|
|
DataRefItem<string, string> riLubro = listaDR.Find(x => x.Key == string.Format("Lubro_{0:00}_Count", i + 1));
|
|
|
|
|
// recupero valori...
|
|
|
|
|
currLubroCount[i] = Convert.ToUInt32(riLubro.Value);
|
|
|
|
|
istLubroCount[i] = new sampleVect();
|
|
|
|
|
}
|
|
|
|
|
currSlittaMag = new uint[currAdpConf.nSlittaMag];
|
|
|
|
|
istSlittaMag = new sampleVect[currAdpConf.nSlittaMag];
|
|
|
|
|
for (int i = 0; i < currAdpConf.nSlittaMag; i++)
|
|
|
|
|
{
|
|
|
|
|
// leggo tutti i dati...
|
|
|
|
|
List<DataRefItem<string, string>> listaDR = currAdpConf.SlittaMag[i].dataRefList;
|
|
|
|
|
// punto all'item
|
|
|
|
|
DataRefItem<string, string> riSlittaMag = listaDR.Find(x => x.Key == string.Format("SlittaMagazzino_{0:00}_Count", i + 1));
|
|
|
|
|
// recupero valori...
|
|
|
|
|
currSlittaMag[i] = Convert.ToUInt32(riSlittaMag.Value);
|
|
|
|
|
istSlittaMag[i] = new sampleVect();
|
|
|
|
|
}
|
|
|
|
|
currProtMag = new uint[currAdpConf.nProtMag];
|
|
|
|
|
istProtMag = new sampleVect[currAdpConf.nProtMag];
|
|
|
|
|
for (int i = 0; i < currAdpConf.nProtMag; i++)
|
|
|
|
|
{
|
|
|
|
|
// leggo tutti i dati...
|
|
|
|
|
List<DataRefItem<string, string>> listaDR = currAdpConf.ProtMag[i].dataRefList;
|
|
|
|
|
// punto all'item
|
|
|
|
|
DataRefItem<string, string> riProtMag = listaDR.Find(x => x.Key == string.Format("ProtMagazzino_{0:00}_Count", i + 1));
|
|
|
|
|
// recupero valori...
|
|
|
|
|
currProtMag[i] = Convert.ToUInt32(riProtMag.Value);
|
|
|
|
|
istProtMag[i] = new sampleVect();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//mAlarmSystem.Normal();
|
|
|
|
|
mAlarmCNC.Normal();
|
|
|
|
|
mAlarmPLC.Normal();
|
|
|
|
|
#endif
|
|
|
|
|
//mAlarmGeneral.Normal();
|
|
|
|
|
adpTryRestart = true;
|
|
|
|
|
parentForm.displayTaskAndWait("Adapter Started!");
|
|
|
|
|
}
|
|
|
|
@@ -525,30 +276,11 @@ namespace IOB_WIN
|
|
|
|
|
|
|
|
|
|
// chiudo la connessione all'adapter...
|
|
|
|
|
tryDisconnect();
|
|
|
|
|
#if false
|
|
|
|
|
// Stop everything...
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
mAdapter.Stop();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception exc)
|
|
|
|
|
{
|
|
|
|
|
lg.Error(exc, "Eccezione in chiusura Adapter");
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
dtStopAdp = DateTime.Now;
|
|
|
|
|
#if false
|
|
|
|
|
adpPortNum = mAdapter.Port;
|
|
|
|
|
#endif
|
|
|
|
|
adpTryRestart = tryRestart;
|
|
|
|
|
adpRunning = false;
|
|
|
|
|
// chiudo!
|
|
|
|
|
parentForm.resetProgBar();
|
|
|
|
|
#if false
|
|
|
|
|
parentForm.dataMonitor_1 = "... not connected, waiting for data ...";
|
|
|
|
|
parentForm.dataMonitor_2 = "";
|
|
|
|
|
parentForm.dataMonitor_3 = "";
|
|
|
|
|
#endif
|
|
|
|
|
parentForm.displayTaskAndWait("Adapter Stopped.");
|
|
|
|
|
parentForm.commPlcActive = false;
|
|
|
|
|
}
|
|
|
|
@@ -681,59 +413,9 @@ namespace IOB_WIN
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void checkSavePersDataLayer()
|
|
|
|
|
{
|
|
|
|
|
#if false
|
|
|
|
|
// aggiungo dettaglio valori ultimi codici MST
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
string codM = "";
|
|
|
|
|
string codS = "";
|
|
|
|
|
string codT = "";
|
|
|
|
|
for (int i = 0; i < currAdpConf.nPath; i++)
|
|
|
|
|
{
|
|
|
|
|
codM = vettPath[i].mPathCodM.Value.ToString().Replace("UNAVAILABLE", "n.d.");
|
|
|
|
|
codS = vettPath[i].mPathCodS.Value.ToString().Replace("UNAVAILABLE", "n.d.");
|
|
|
|
|
codT = vettPath[i].mPathCodT.Value.ToString().Replace("UNAVAILABLE", "n.d.");
|
|
|
|
|
// accodo ultimi codici in visualizzazione...
|
|
|
|
|
sb.AppendLine(string.Format("P{0} last MST: {1} | {2} | {3}", i + 1, codM, codS, codT));
|
|
|
|
|
}
|
|
|
|
|
parentForm.dataMonitor_1 += sb.ToString();
|
|
|
|
|
|
|
|
|
|
if (persistenceLayer != null)
|
|
|
|
|
{
|
|
|
|
|
bool needSave = false;
|
|
|
|
|
// verifica se si debba aggiornare XML (e salva in adapter dati vari)
|
|
|
|
|
needSave = procOreMaccOn(needSave);
|
|
|
|
|
needSave = procOreMaccLav(needSave);
|
|
|
|
|
needSave = procProgrName(needSave);
|
|
|
|
|
needSave = procPartId(needSave);
|
|
|
|
|
needSave = procPzProd(needSave);
|
|
|
|
|
needSave = procGiriTotUnOp(needSave);
|
|
|
|
|
needSave = procNumCU(needSave);
|
|
|
|
|
needSave = procCounters(needSave);
|
|
|
|
|
needSave = procMovTotAssi(needSave);
|
|
|
|
|
needSave = procAccTimeAssi(needSave);
|
|
|
|
|
needSave = procNumInvAssi(needSave);
|
|
|
|
|
needSave = procVacPump(needSave);
|
|
|
|
|
needSave = procVacAct(needSave);
|
|
|
|
|
needSave = procLubro(needSave);
|
|
|
|
|
needSave = procSlittaMag(needSave);
|
|
|
|
|
needSave = procProtMag(needSave);
|
|
|
|
|
|
|
|
|
|
// salvo se necessario!
|
|
|
|
|
if (needSave) parentForm.persistData();
|
|
|
|
|
// -------------------------------------------
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
public void resetDebugConsole()
|
|
|
|
|
{
|
|
|
|
|
#if false
|
|
|
|
|
// resetto console debug...
|
|
|
|
|
parentForm.dataMonitor_1 = "";
|
|
|
|
|
parentForm.dataMonitor_2 = "";
|
|
|
|
|
parentForm.dataMonitor_3 = "";
|
|
|
|
|
// indico msg allarme NON inviati
|
|
|
|
|
alarmMsgDispl = false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@@ -955,19 +637,6 @@ namespace IOB_WIN
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual void forceAlarmCheck()
|
|
|
|
|
{
|
|
|
|
|
#if false
|
|
|
|
|
// carico status allarmi (completo)
|
|
|
|
|
StFlag32 forceAlarm = (StFlag32)unchecked((int)UInt32.MaxValue);
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
refreshAlarmState(forceAlarm, false);
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
lg.Error("Errore in fase di esecuzione di forceAlarmCheck");
|
|
|
|
|
}
|
|
|
|
|
if (utils.CRB("recTime")) logTimeResults();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|