@if (DoorsList == null || DoorsList.Count == 0)
- { }
+ {
+
+ }
else
{
int idxCount = 0;
@@ -26,7 +33,20 @@
imgPath = $"images/LogoEgw{idxCount % 5:00}.png";
idxCount++;
-
+ @if (isCloneMode)
+ {
+
+
+ }
+ else if (isAddRemMode)
+ {
+
+ }
+ else
+ {
+
+
+ }
}
diff --git a/WebDoorCreator.UI/Components/DoorMan/DoorList.razor.cs b/WebDoorCreator.UI/Components/DoorMan/DoorList.razor.cs
index 8a3d739..db462d3 100644
--- a/WebDoorCreator.UI/Components/DoorMan/DoorList.razor.cs
+++ b/WebDoorCreator.UI/Components/DoorMan/DoorList.razor.cs
@@ -177,6 +177,47 @@ namespace WebDoorCreator.UI.Components.DoorMan
// rimando alla pagina... dettaglio...
NavManager.NavigateTo($"/DoorDefinition?idOrd={currOrderId}&idDoor={doorId}");
}
+ ///
+ /// Path del servizio di recupero SVG delle porte
+ ///
+ ///
+ ///
+ protected string DoorSvgUrl(int doorId)
+ {
+ return $"api/DoorImage/GetImage.svg?DoorId={doorId}";
+ }
+
+ protected bool isCloneMode { get; set; }
+ protected bool isAddRemMode { get; set; }
+
+ protected async void setCloneDoorMode(string message)
+ {
+ await Task.Delay(1);
+ isCloneMode = !isCloneMode;
+ isAddRemMode = false;
+ await InvokeAsync(StateHasChanged);
+ }
+ protected async void setAddRemDoor()
+ {
+ await Task.Delay(1);
+ isAddRemMode = !isAddRemMode;
+ isCloneMode = false;
+ await InvokeAsync(StateHasChanged);
+ }
+
+ protected async Task doClone(string message)
+ {
+ var door2Clone = DoorsList?.Where(x => x.DoorId == int.Parse(message)).FirstOrDefault();
+
+ if (door2Clone != null)
+ {
+ var doorOpToAdd = door2Clone.ObjClone(userId);
+
+ // salvo!
+ var done = await WDService.DoorInsert(doorOpToAdd);
+ await ReloadData();
+ }
+ }
protected async void sendToAbh(int ordId, int orderStat)
{
if (orderStat == 10)
@@ -222,5 +263,26 @@ namespace WebDoorCreator.UI.Components.DoorMan
}
}
}
+
+ protected async Task addOneDoorNumber(string msg1, string msg2)
+ {
+ //var door = new DoorModel();
+ var done = await WDService.DoorModQty(int.Parse(msg1), int.Parse(msg2), true);
+ if (done)
+ {
+ await InvokeAsync(StateHasChanged);
+ await ReloadData();
+ }
+ }
+ protected async Task removeOneDoorNumber(string msg1, string msg2)
+ {
+ //var door = new DoorModel();
+ var done = await WDService.DoorModQty(int.Parse(msg1), int.Parse(msg2), false);
+ if (done)
+ {
+ await InvokeAsync(StateHasChanged);
+ await ReloadData();
+ }
+ }
}
}
\ No newline at end of file
diff --git a/WebDoorCreator.UI/Components/Hardware/HardwareList.razor b/WebDoorCreator.UI/Components/Hardware/HardwareList.razor
index ee2b8f8..34595b1 100644
--- a/WebDoorCreator.UI/Components/Hardware/HardwareList.razor
+++ b/WebDoorCreator.UI/Components/Hardware/HardwareList.razor
@@ -4,16 +4,9 @@
@if (HwToShow != null)
{
-
-
-
- @(translate(HwToShow.Label))
-
hwToAdd()">
-
-
-
+
-
+
diff --git a/WebDoorCreator.UI/Components/Hardware/HardwareList.razor.cs b/WebDoorCreator.UI/Components/Hardware/HardwareList.razor.cs
index bcdc041..afa1bf9 100644
--- a/WebDoorCreator.UI/Components/Hardware/HardwareList.razor.cs
+++ b/WebDoorCreator.UI/Components/Hardware/HardwareList.razor.cs
@@ -21,8 +21,10 @@ namespace WebDoorCreator.UI.Components.Hardware
[CascadingParameter]
public string UserId { get; set; } = "";
+#if false
[Parameter]
- public bool isDoorOpConf { get; set; }
+ public bool isDoorOpConf { get; set; }
+#endif
#endregion Public Properties
@@ -191,10 +193,7 @@ namespace WebDoorCreator.UI.Components.Hardware
{
HwToShow = null;
}
- if (!isDoorOpConf)
- {
- await ReloadData();
- }
+ await ReloadData();
}
protected string setBgColor(string ObjId)
@@ -247,6 +246,14 @@ namespace WebDoorCreator.UI.Components.Hardware
}
}
+ protected async Task setRefOnDelete(bool isDel)
+ {
+ if (isDel)
+ {
+ await ReloadData();
+ }
+ }
+
protected int getInstNumber(string hwCode)
{
int answ = 0;
diff --git a/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor b/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor
index 4bfdacf..f5af628 100644
--- a/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor
+++ b/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor
@@ -1,12 +1,27 @@
-@if (DoorOpList != null)
+@if (isLoading)
{
-
- @foreach (var item in DoorOpList)
- {
-
-
+
+}
+else
+{
+ @if (DoorOpList != null)
+ {
+
+
+
+ @(translate(HwLabel))
+
hwToAdd()">
+
- }
-
+
+
+ @foreach (var item in DoorOpList)
+ {
+
+
+
+ }
+
+ }
}
diff --git a/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor.cs b/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor.cs
index 09d016e..91932b5 100644
--- a/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor.cs
+++ b/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor.cs
@@ -1,16 +1,23 @@
using Microsoft.AspNetCore.Components;
+using Newtonsoft.Json;
+using WebDoorCreator.Data;
using WebDoorCreator.Data.DbModels;
+using WebDoorCreator.UI.Components.DoorMan;
using WebDoorCreator.UI.Data;
+using static WebDoorCreator.UI.Data.WDCRefreshService;
namespace WebDoorCreator.UI.Components.Hardware
{
- public partial class HardwareNewPanel
+ public partial class HardwareNewPanel : IDisposable
{
#region Public Properties
[Parameter]
public int DoorId { get; set; } = 0;
+ [Parameter]
+ public EventCallback
E_act2Rel { get; set; }
+
[Parameter]
public EventCallback E_recordUpdate { get; set; }
@@ -22,50 +29,182 @@ namespace WebDoorCreator.UI.Components.Hardware
[Parameter]
public string HwCode { get; set; } = "";
+ [Parameter]
+ public string HwLabel { get; set; } = "";
[Parameter]
public string Lingua { get; set; } = "EN";
+ [CascadingParameter]
+ public string UserId { get; set; } = "";
- protected bool _isDoorOpConf { get; set;} = false;
-
- [Parameter]
- public bool isDoorOpConf
- {
- get => _isDoorOpConf;
- set
- {
- if (_isDoorOpConf != value)
- {
- _isDoorOpConf = value;
- var pupd = InvokeAsync(async () => await ReloadData());
- }
- }
- }
+ protected bool _isDoorOpConf { get; set; } = false;
#endregion Public Properties
#region Protected Properties
protected List? DoorOpList { get; set; } = null!;
+ protected List DoorOp2ModList { get; set; } = new List();
protected int instNum { get; set; } = 1;
[Inject]
- protected WebDoorCreatorService WDCService { get; set; } = null!;
+ protected WDCRefreshService WDCRefresh { get; set; } = null!;
+ [Inject]
+ protected WebDoorCreatorService WDCService { get; set; } = null!;
+ [Inject]
+ protected WDCVocabularyService WDVService { get; set; } = null!;
+
+ public void Dispose()
+ {
+ WDCRefresh.EA_ConfDoorOp -= WDCRefresh_EA_ConfDoorOp;
+ }
+
+ protected override async Task OnInitializedAsync()
+ {
+ await Task.Delay(1);
+ WDCRefresh.EA_ConfDoorOp += WDCRefresh_EA_ConfDoorOp;
+ //return base.OnInitializedAsync();
+ }
+
+ protected string translate(string lemma)
+ {
+ string answ = "";
+
+ answ = WDVService.Traduci(Lingua, lemma);
+
+ return answ;
+ }
+
+ private void WDCRefresh_EA_ConfDoorOp(object? sender, EventArgs e)
+ {
+ DOPEventArgs currArgs = (DOPEventArgs)e;
+ // SE sono sula porta indicata + objId corretto --> refresh
+ if (currArgs.DoorId == DoorId && currArgs.ObjectId == HwCode)
+ {
+ var pupd = InvokeAsync(async () => await ReloadData());
+ }
+ }
#endregion Protected Properties
#region Protected Methods
- [Inject]
- protected WDCRefreshService WDCRService { get; set; } = null!;
-
protected bool B_doorOpUpd
{
get => WDCRService.isDoorOpUpd;
set => WDCRService.isDoorOpUpd = value;
}
+ [Inject]
+ protected WDCRefreshService WDCRService { get; set; } = null!;
+ protected async Task hwToAdd()
+ {
+ await Task.Delay(1);
+ DateTime adesso = DateTime.Now;
+ List listOp = new List();
+
+ if (HwCode != null)
+ {
+ if (DoorOp2ModList.Count == 0)
+ {
+ var listRecordFolder = await WDCService.ListValuesGetAll(HwCode, "Folder");
+ var listRecordTmp = await WDCService.ListValuesGetAll(HwCode, "template");
+ if (listRecordTmp!.Count == 0)
+ {
+ listRecordTmp = await WDCService.ListValuesGetAll(HwCode, "shape");
+ }
+ Dictionary> defaultDict = new Dictionary>();
+ List listDefVal = new List();
+ Dictionary actDict = new Dictionary();
+ List defaultParamsList = new List();
+ string default2Design = "";
+
+ if (listRecordFolder != null)
+ {
+ var firstFolder = listRecordFolder.FirstOrDefault();
+ if (firstFolder != null)
+ {
+ actDict.Add(firstFolder.FieldName, firstFolder.Value.Trim());
+ if (listRecordTmp != null)
+ {
+ var listRecordTemplates = listRecordTmp.Where(x => x.Value.Contains(firstFolder.Value)).ToList();
+ if (listRecordTemplates != null)
+ {
+ var firstTemplate = listRecordTemplates.FirstOrDefault();
+ if (firstTemplate != null)
+ {
+ if (firstTemplate.DefaultVal != "")
+ {
+ default2Design = firstTemplate.DefaultVal;
+ }
+ else
+ {
+ default2Design = "1";
+ }
+
+ actDict.Add(firstTemplate.FieldName, firstTemplate.Value.Trim());
+ }
+ }
+ }
+ }
+ var listRecordGP = await WDCService.ListValuesGetAll(HwCode, $"Graphic Parameters{default2Design}");
+ if (listRecordGP != null)
+ {
+ foreach (var item in listRecordGP)
+ {
+ if (item.isSerializable && item.DefaultVal.Contains(","))
+ {
+ listDefVal = item.DefaultVal.Trim().Split(",").ToList();
+ actDict.Add(item.Value.Trim(), item.DefaultVal.Trim().Split(",")[0].Split("/")[0]);
+ }
+ else
+ {
+ if (item.DefaultVal.Contains("/"))
+ {
+ listDefVal = new List() { item.DefaultVal.Trim().Split("/")[0] };
+ actDict.Add(item.Value.Trim(), item.DefaultVal.Trim().Split("/")[0]);
+ }
+ else
+ {
+ listDefVal = new List() { item.DefaultVal.Trim() };
+ actDict.Add(item.Value.Trim(), item.DefaultVal.Trim());
+ }
+ }
+ //defaultParamsList.Add(listDefVal);
+ defaultDict.Add(item.Value.Trim(), listDefVal);
+ }
+ //actDict.Add(HwToShow.TableName, actParamsList);
+
+ var jsonDef = JsonConvert.SerializeObject(defaultDict);
+ var jsonAct = JsonConvert.SerializeObject(actDict);
+
+ DoorOpModel doorOpToAdd = new DoorOpModel()
+ {
+ DateIns = adesso,
+ DateMod = adesso,
+ UserIdIns = UserId,
+ UserIdMod = UserId,
+ ObjectId = HwCode,
+ DoorId = DoorId,
+ JsoncConfigVal = jsonDef,
+ JsoncActVal = jsonAct
+ };
+ listOp.Add(doorOpToAdd);
+ // salvo Door OP associate
+ bool fatto = await WDCService.DoorOpInsert(DoorId, listOp);
+
+ if (fatto)
+ {
+ //hwAdd = fatto;
+ await InvokeAsync(StateHasChanged);
+ }
+ }
+ }
+ }
+ }
+ }
+
///
/// Gestione update da oggetto sottostante
///
@@ -80,15 +219,14 @@ namespace WebDoorCreator.UI.Components.Hardware
var item2rem = DoorOpList.Where(x => x.DoorOpId == currItem.DoorOpId).FirstOrDefault();
if (item2rem != null)
{
- DoorOpList.Remove(item2rem);
+ DoorOp2ModList.Remove(item2rem);
}
await Task.Delay(1);
B_doorOpUpd = true;
- DoorOpList.Add(currItem);
+ DoorOp2ModList.Add(currItem);
}
}
-
protected override async Task OnParametersSetAsync()
{
await ReloadData();
@@ -98,16 +236,38 @@ namespace WebDoorCreator.UI.Components.Hardware
#region Private Methods
+ protected bool isLoading { get; set; } = false;
+
+ protected List? ListRecord { get; set; } = null;
+
+ protected async Task setRefOnDelete(bool isDel)
+ {
+ if (isDel)
+ {
+ await ReloadData();
+ }
+ }
+
private async Task ReloadData()
{
- var ListRecord = await WDCService.DoorOpGetByDoorId(DoorId);
+ isLoading = true;
+ //await Task.Delay(50);
+ await InvokeAsync(StateHasChanged);
+ ListRecord = null;
+ DoorOpList = null;
+ await Task.Delay(1);
+ ListRecord = await WDCService.DoorOpGetByDoorId(DoorId);
var tempListVal = await WDCService.ListValuesGetAll(HwCode, "Folder");
if (ListRecord != null)
{
DoorOpList = ListRecord.Where(x => (x.DoorId == DoorId) && (x.ObjectId == HwCode)).ToList();
}
+ isLoading = false;
+ //await Task.Delay(50);
+ await InvokeAsync(StateHasChanged);
}
-
#endregion Private Methods
+
+
}
}
\ No newline at end of file
diff --git a/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor.css b/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor.css
new file mode 100644
index 0000000..e6277c0
--- /dev/null
+++ b/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor.css
@@ -0,0 +1,49 @@
+.rectangle {
+ height: 2.75rem;
+ width: 75%;
+ background: #CFD8DC;
+ position: relative;
+ margin-bottom: 4rem;
+ margin-top: 1.25rem;
+ border-radius: 0.8rem;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ color: #000;
+ font-weight: bold;
+}
+.circle {
+ position: absolute;
+ height: 6.25rem;
+ width: 6.25rem;
+ border-radius: 50%;
+ border: 4px solid #CFD8DC;
+ left: 100%;
+ margin-left: -1.563rem;
+ top: -1.5rem;
+ background: black;
+}
+.rectangleDetail {
+ height: 2.75rem;
+ width: 75%;
+ position: relative;
+ margin-bottom: 4rem;
+ margin-top: 1.25rem;
+ border-radius: 0.8rem;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ color: #000;
+ font-weight: bold;
+}
+.circleDetail {
+ position: absolute;
+ height: 6.25rem;
+ width: 6.25rem;
+ border-radius: 50%;
+ border: 4px solid #CFD8DC;
+ left: 100%;
+ margin-left: -1.563rem;
+ top: -1.5rem;
+ background: black;
+}
\ No newline at end of file
diff --git a/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor.less b/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor.less
new file mode 100644
index 0000000..5030bb7
--- /dev/null
+++ b/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor.less
@@ -0,0 +1,58 @@
+.rectangle {
+ height: 2.75rem;
+ width: 75%;
+ background: #CFD8DC;
+ position: relative;
+ margin-bottom: 4rem;
+ margin-top: 1.25rem;
+ border-radius: 0.8rem;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ color: #000;
+ font-weight: bold;
+}
+
+.circle {
+ position: absolute;
+ height: 6.25rem;
+ width: 6.25rem;
+ border-radius: 50%;
+ border: 4px solid #CFD8DC;
+ left: 100%;
+ margin-left: -1.563rem;
+ top: -1.5rem;
+ background: black;
+}
+
+
+.rectangleDetail {
+ height: 2.75rem;
+ width: 75%;
+ //background: #CFD8DC;
+ position: relative;
+ margin-bottom: 4rem;
+ margin-top: 1.25rem;
+ border-radius: 0.8rem;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ color: #000;
+ font-weight: bold;
+}
+
+.circleDetail {
+ position: absolute;
+ height: 6.25rem;
+ width: 6.25rem;
+ border-radius: 50%;
+ border: 4px solid #CFD8DC;
+ left: 100%;
+ margin-left: -1.563rem;
+ top: -1.5rem;
+ background: black;
+}
+
+.all {
+ //width: 72rem;
+}
diff --git a/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor.min.css b/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor.min.css
new file mode 100644
index 0000000..7450833
--- /dev/null
+++ b/WebDoorCreator.UI/Components/Hardware/HardwareNewPanel.razor.min.css
@@ -0,0 +1 @@
+.rectangle{height:2.75rem;width:75%;background:#cfd8dc;position:relative;margin-bottom:4rem;margin-top:1.25rem;border-radius:.8rem;display:flex;flex-wrap:wrap;align-items:center;color:#000;font-weight:bold;}.circle{position:absolute;height:6.25rem;width:6.25rem;border-radius:50%;border:4px solid #cfd8dc;left:100%;margin-left:-1.563rem;top:-1.5rem;background:#000;}.rectangleDetail{height:2.75rem;width:75%;position:relative;margin-bottom:4rem;margin-top:1.25rem;border-radius:.8rem;display:flex;flex-wrap:wrap;align-items:center;color:#000;font-weight:bold;}.circleDetail{position:absolute;height:6.25rem;width:6.25rem;border-radius:50%;border:4px solid #cfd8dc;left:100%;margin-left:-1.563rem;top:-1.5rem;background:#000;}
\ No newline at end of file
diff --git a/WebDoorCreator.UI/Components/Hardware/HwSingleInstance.razor.cs b/WebDoorCreator.UI/Components/Hardware/HwSingleInstance.razor.cs
index 08e60f0..c8d354e 100644
--- a/WebDoorCreator.UI/Components/Hardware/HwSingleInstance.razor.cs
+++ b/WebDoorCreator.UI/Components/Hardware/HwSingleInstance.razor.cs
@@ -2,9 +2,11 @@ using Microsoft.AspNetCore.Components;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.JSInterop;
using Newtonsoft.Json;
+using System.Security.Policy;
using WebDoorCreator.Data.DbModels;
using WebDoorCreator.Data.Services;
using WebDoorCreator.UI.Data;
+using static WebDoorCreator.UI.Data.WDCRefreshService;
namespace WebDoorCreator.UI.Components.Hardware
{
@@ -17,6 +19,8 @@ namespace WebDoorCreator.UI.Components.Hardware
[Parameter]
public EventCallback E_recordUpdate { get; set; }
+ [Parameter]
+ public EventCallback E_act2Rel { get; set; }
[Parameter]
public string HwCode { get; set; } = "";
@@ -160,9 +164,11 @@ namespace WebDoorCreator.UI.Components.Hardware
List doorOpAddList = new List() { doorOpToAdd };
// salvo!
- await WDCService.DoorOpInsert(DoorOpInst.DoorId, doorOpAddList);
+ var done = await WDCService.DoorOpInsert(DoorOpInst.DoorId, doorOpAddList);
+ await E_act2Rel.InvokeAsync(done);
await FullReloadData();
}
+#if false
protected async Task doConfirm()
{
@@ -177,15 +183,17 @@ namespace WebDoorCreator.UI.Components.Hardware
DoorOpInst.GraphicParams = graphicParams;
// salvo!
await doSave();
- }
+ }
+#endif
protected async Task doDeleteInst()
{
- var done = await JSRuntime.InvokeAsync("confirm", "Delete PERMANENTLY the current record?");
+ var delConf = await JSRuntime.InvokeAsync("confirm", "Delete PERMANENTLY the current record?");
- if (done)
+ if (delConf)
{
- await WDCService.DoorOpDelete(DoorOpInst);
+ var done = await WDCService.DoorOpDelete(DoorOpInst);
+ await E_act2Rel.InvokeAsync(done);
await FullReloadData();
}
}
@@ -231,6 +239,35 @@ namespace WebDoorCreator.UI.Components.Hardware
await FullReloadData();
}
+
+#if false
+
+ private void WDCRefresh_EA_ConfDoorOp(object? sender, EventArgs e)
+ {
+ DOPEventArgs currArgs = (DOPEventArgs)e;
+ // SE sono sula porta indicata + objId corretto --> refresh
+ if (currArgs.DoorId == DoorOpInst.DoorId && currArgs.DoorOpId == DoorOpInst.DoorOpId && currArgs.ObjectId == DoorOpInst.ObjectId)//&& currArgs.ObjectId == obid )
+ {
+ var pupd = InvokeAsync(async () => await FullReloadData());
+ }
+ }
+
+ public void Dispose()
+ {
+ WDCRefresh.EA_ConfDoorOp -= WDCRefresh_EA_ConfDoorOp;
+ }
+
+ [Inject]
+ protected WDCRefreshService WDCRefresh { get; set; } = null!;
+
+ protected override async Task OnInitializedAsync()
+ {
+ await FullReloadData();
+ await Task.Delay(1);
+ WDCRefresh.EA_ConfDoorOp += WDCRefresh_EA_ConfDoorOp;
+ }
+#endif
+
protected string translate(string lemma)
{
string answ = "";
@@ -252,7 +289,7 @@ namespace WebDoorCreator.UI.Components.Hardware
private string pathFinder(int id)
{
- string answ = $"HwPdfConfirm?idHwInst={id}";
+ string answ = $"HwPdfConfirm?doorOpId={id}&doorId={DoorOpInst.DoorId}&objectId={DoorOpInst.ObjectId}";
return answ;
}
diff --git a/WebDoorCreator.UI/Components/Order/OrderList.razor b/WebDoorCreator.UI/Components/Order/OrderList.razor
index 675a1c4..314be16 100644
--- a/WebDoorCreator.UI/Components/Order/OrderList.razor
+++ b/WebDoorCreator.UI/Components/Order/OrderList.razor
@@ -37,10 +37,10 @@ else
*@
- @* @if (item.OrderStatus < (int)Core.Enum.OrderStatus.Sent)
+ @if (item.OrderStatus <= 10)
{
- }*@
+ }
|
}
diff --git a/WebDoorCreator.UI/Components/SvgComp/DoorSvgObj.razor b/WebDoorCreator.UI/Components/SvgComp/DoorSvgObj.razor
index 451d005..9a79579 100644
--- a/WebDoorCreator.UI/Components/SvgComp/DoorSvgObj.razor
+++ b/WebDoorCreator.UI/Components/SvgComp/DoorSvgObj.razor
@@ -1,14 +1,14 @@