diff --git a/Api/Utility/General.cs b/Api/Utility/General.cs
index 4c79ac1..3f924f6 100644
--- a/Api/Utility/General.cs
+++ b/Api/Utility/General.cs
@@ -37,7 +37,14 @@ namespace Milimoe.FunGame.Core.Api.Utility
///
///
///
- public static bool IsUserName(string str) => Regex.IsMatch(str, @"^[\u4e00-\u9fa5A-Za-z0-9]+$");
+ public static bool IsUserName(string str) => Regex.IsMatch(str, @"^[\u4e00-\u9fffA-Za-z0-9]+$");
+
+ ///
+ /// 判断字符串是否是全中文的字符
+ ///
+ ///
+ ///
+ public static bool IsChineseName(string str) => Regex.IsMatch(str, @"^[\u4e00-\u9fff]+$");
///
/// 获取用户名长度
diff --git a/Api/Utility/PluginConfig.cs b/Api/Utility/PluginConfig.cs
index b2f1980..894871f 100644
--- a/Api/Utility/PluginConfig.cs
+++ b/Api/Utility/PluginConfig.cs
@@ -1,4 +1,3 @@
-using System.Text;
using System.Text.Json;
using Milimoe.FunGame.Core.Library.Constant;
@@ -137,7 +136,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
{
Directory.CreateDirectory(dpath);
}
- using StreamWriter writer = new(fpath, false, Encoding.Unicode);
+ using StreamWriter writer = new(fpath, false, General.DefaultEncoding);
writer.WriteLine(json);
writer.Flush();
}
diff --git a/Entity/Character/Character.cs b/Entity/Character/Character.cs
index c14d576..d80208d 100644
--- a/Entity/Character/Character.cs
+++ b/Entity/Character/Character.cs
@@ -1,15 +1,21 @@
-using Milimoe.FunGame.Core.Interface.Entity;
+using Milimoe.FunGame.Core.Api.Utility;
+using Milimoe.FunGame.Core.Interface.Entity;
using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Entity
{
public class Character : BaseEntity, ICopyable
{
+ ///
+ /// 角色的姓
+ ///
+ public override string Name { get; set; } = "";
+
///
/// 角色的名字
///
public string FirstName { get; set; } = "";
-
+
///
/// 角色的昵称
///
@@ -263,7 +269,8 @@ namespace Milimoe.FunGame.Core.Entity
public override string ToString()
{
- string str = (Name + " " + FirstName).Trim();
+ bool isChineseName = NetworkUtility.IsChineseName(Name + FirstName);
+ string str = isChineseName ? (Name + FirstName).Trim() : (Name + " " + FirstName).Trim();
if (NickName != "")
{
if (str != "") str += ", ";
diff --git a/Interface/Base/IEntityConverter.cs b/Interface/Base/IEntityConverter.cs
index ed1ecca..a69655f 100644
--- a/Interface/Base/IEntityConverter.cs
+++ b/Interface/Base/IEntityConverter.cs
@@ -2,8 +2,10 @@
namespace Milimoe.FunGame.Core.Interface.Base
{
- internal interface IEntityConverter
+ public interface IEntityConverter
{
- public void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref T? result);
+ public T NewInstance();
+
+ public void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref T result);
}
}
diff --git a/Library/Common/Architecture/BaseEntityConverter.cs b/Library/Common/Architecture/BaseEntityConverter.cs
index 33309a9..143e102 100644
--- a/Library/Common/Architecture/BaseEntityConverter.cs
+++ b/Library/Common/Architecture/BaseEntityConverter.cs
@@ -16,6 +16,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Architecture
if (reader.TokenType == JsonTokenType.PropertyName)
{
+ result ??= NewInstance();
string propertyName = reader.GetString() ?? "";
reader.Read();
ReadPropertyName(ref reader, propertyName, options, ref result);
@@ -25,6 +26,8 @@ namespace Milimoe.FunGame.Core.Library.Common.Architecture
return result;
}
- public abstract void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref T? result);
+ public abstract T NewInstance();
+
+ public abstract void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref T result);
}
}
diff --git a/Library/Common/JsonConverter/CharacterConverter.cs b/Library/Common/JsonConverter/CharacterConverter.cs
new file mode 100644
index 0000000..4b23514
--- /dev/null
+++ b/Library/Common/JsonConverter/CharacterConverter.cs
@@ -0,0 +1,202 @@
+using System.Text.Json;
+using Milimoe.FunGame.Core.Api.Utility;
+using Milimoe.FunGame.Core.Entity;
+using Milimoe.FunGame.Core.Library.Common.Architecture;
+using Milimoe.FunGame.Core.Library.Constant;
+
+namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
+{
+ public class CharacterConverter : BaseEntityConverter
+ {
+ public override Character NewInstance()
+ {
+ return Factory.GetCharacter();
+ }
+
+ public override void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref Character result)
+ {
+ switch (propertyName)
+ {
+ case nameof(Character.Name):
+ result.Name = reader.GetString() ?? "";
+ break;
+ case nameof(Character.FirstName):
+ result.FirstName = reader.GetString() ?? "";
+ break;
+ case nameof(Character.NickName):
+ result.NickName = reader.GetString() ?? "";
+ break;
+ case nameof(Character.MagicType):
+ result.MagicType = (MagicType)reader.GetInt32();
+ break;
+ case nameof(Character.FirstRoleType):
+ result.FirstRoleType = (RoleType)reader.GetInt32();
+ break;
+ case nameof(Character.SecondRoleType):
+ result.SecondRoleType = (RoleType)reader.GetInt32();
+ break;
+ case nameof(Character.ThirdRoleType):
+ result.ThirdRoleType = (RoleType)reader.GetInt32();
+ break;
+ case nameof(Character.RoleRating):
+ result.RoleRating = (RoleRating)reader.GetInt32();
+ break;
+ case nameof(Character.Promotion):
+ result.Promotion = reader.GetInt32();
+ break;
+ case nameof(Character.Level):
+ result.Level = reader.GetInt32();
+ break;
+ case nameof(Character.EXP):
+ result.EXP = reader.GetDecimal();
+ break;
+ case nameof(Character.BaseHP):
+ result.BaseHP = reader.GetDecimal();
+ break;
+ case nameof(Character.HP):
+ result.HP = reader.GetDecimal();
+ break;
+ case nameof(Character.BaseMP):
+ result.BaseMP = reader.GetDecimal();
+ break;
+ case nameof(Character.MP):
+ result.MP = reader.GetDecimal();
+ break;
+ case nameof(Character.EP):
+ result.EP = reader.GetDecimal();
+ break;
+ case nameof(Character.BaseATK):
+ result.BaseATK = reader.GetDecimal();
+ break;
+ case nameof(Character.ATK):
+ result.ATK = reader.GetDecimal();
+ break;
+ case nameof(Character.BaseDEF):
+ result.BaseDEF = reader.GetDecimal();
+ break;
+ case nameof(Character.DEF):
+ result.DEF = reader.GetDecimal();
+ break;
+ case nameof(Character.PDR):
+ result.PDR = reader.GetDecimal();
+ break;
+ case nameof(Character.MDF):
+ result.MDF = reader.GetDecimal();
+ break;
+ case nameof(Character.PhysicalPenetration):
+ result.PhysicalPenetration = reader.GetDecimal();
+ break;
+ case nameof(Character.MagicalPenetration):
+ result.MagicalPenetration = reader.GetDecimal();
+ break;
+ case nameof(Character.HR):
+ result.HR = reader.GetDecimal();
+ break;
+ case nameof(Character.MR):
+ result.MR = reader.GetDecimal();
+ break;
+ case nameof(Character.ER):
+ result.ER = reader.GetDecimal();
+ break;
+ case nameof(Character.BaseSTR):
+ result.BaseSTR = reader.GetDecimal();
+ break;
+ case nameof(Character.BaseAGI):
+ result.BaseAGI = reader.GetDecimal();
+ break;
+ case nameof(Character.BaseINT):
+ result.BaseINT = reader.GetDecimal();
+ break;
+ case nameof(Character.STR):
+ result.STR = reader.GetDecimal();
+ break;
+ case nameof(Character.AGI):
+ result.AGI = reader.GetDecimal();
+ break;
+ case nameof(Character.INT):
+ result.INT = reader.GetDecimal();
+ break;
+ case nameof(Character.STRGrowth):
+ result.STRGrowth = reader.GetDecimal();
+ break;
+ case nameof(Character.AGIGrowth):
+ result.AGIGrowth = reader.GetDecimal();
+ break;
+ case nameof(Character.INTGrowth):
+ result.INTGrowth = reader.GetDecimal();
+ break;
+ case nameof(Character.SPD):
+ result.SPD = reader.GetDecimal();
+ break;
+ case nameof(Character.ActionCoefficient):
+ result.ActionCoefficient = reader.GetDecimal();
+ break;
+ case nameof(Character.AccelerationCoefficient):
+ result.AccelerationCoefficient = reader.GetDecimal();
+ break;
+ case nameof(Character.ATR):
+ result.ATR = reader.GetDecimal();
+ break;
+ case nameof(Character.CritRate):
+ result.CritRate = reader.GetDecimal();
+ break;
+ case nameof(Character.CritDMG):
+ result.CritDMG = reader.GetDecimal();
+ break;
+ case nameof(Character.EvadeRate):
+ result.EvadeRate = reader.GetDecimal();
+ break;
+ }
+ }
+
+ public override void Write(Utf8JsonWriter writer, Character value, JsonSerializerOptions options)
+ {
+ writer.WriteStartObject();
+ writer.WriteString(nameof(Character.Name), value.Name);
+ writer.WriteString(nameof(Character.FirstName), value.FirstName);
+ writer.WriteString(nameof(Character.NickName), value.NickName);
+ writer.WriteNumber(nameof(Character.MagicType), (int)value.MagicType);
+ writer.WriteNumber(nameof(Character.FirstRoleType), (int)value.FirstRoleType);
+ writer.WriteNumber(nameof(Character.SecondRoleType), (int)value.SecondRoleType);
+ writer.WriteNumber(nameof(Character.ThirdRoleType), (int)value.ThirdRoleType);
+ writer.WriteNumber(nameof(Character.RoleRating), (int)value.RoleRating);
+ writer.WriteNumber(nameof(Character.Promotion), value.Promotion);
+ writer.WriteNumber(nameof(Character.Level), value.Level);
+ writer.WriteNumber(nameof(Character.EXP), value.EXP);
+ writer.WriteNumber(nameof(Character.BaseHP), value.BaseHP);
+ writer.WriteNumber(nameof(Character.HP), value.HP);
+ writer.WriteNumber(nameof(Character.BaseMP), value.BaseMP);
+ writer.WriteNumber(nameof(Character.MP), value.MP);
+ writer.WriteNumber(nameof(Character.EP), value.EP);
+ writer.WriteNumber(nameof(Character.BaseATK), value.BaseATK);
+ writer.WriteNumber(nameof(Character.ATK), value.ATK);
+ writer.WriteNumber(nameof(Character.BaseDEF), value.BaseDEF);
+ writer.WriteNumber(nameof(Character.DEF), value.DEF);
+ writer.WriteNumber(nameof(Character.PDR), value.PDR);
+ writer.WriteNumber(nameof(Character.MDF), value.MDF);
+ writer.WriteNumber(nameof(Character.PhysicalPenetration), value.PhysicalPenetration);
+ writer.WriteNumber(nameof(Character.MagicalPenetration), value.MagicalPenetration);
+ writer.WriteNumber(nameof(Character.HR), value.HR);
+ writer.WriteNumber(nameof(Character.MR), value.MR);
+ writer.WriteNumber(nameof(Character.ER), value.ER);
+ writer.WriteNumber(nameof(Character.BaseSTR), value.BaseSTR);
+ writer.WriteNumber(nameof(Character.BaseAGI), value.BaseAGI);
+ writer.WriteNumber(nameof(Character.BaseINT), value.BaseINT);
+ writer.WriteNumber(nameof(Character.STR), value.STR);
+ writer.WriteNumber(nameof(Character.AGI), value.AGI);
+ writer.WriteNumber(nameof(Character.INT), value.INT);
+ writer.WriteNumber(nameof(Character.STRGrowth), value.STRGrowth);
+ writer.WriteNumber(nameof(Character.AGIGrowth), value.AGIGrowth);
+ writer.WriteNumber(nameof(Character.INTGrowth), value.INTGrowth);
+ writer.WriteNumber(nameof(Character.SPD), value.SPD);
+ writer.WriteNumber(nameof(Character.ActionCoefficient), value.ActionCoefficient);
+ writer.WriteNumber(nameof(Character.AccelerationCoefficient), value.AccelerationCoefficient);
+ writer.WriteNumber(nameof(Character.ATR), value.ATR);
+ writer.WriteNumber(nameof(Character.CritRate), value.CritRate);
+ writer.WriteNumber(nameof(Character.CritDMG), value.CritDMG);
+ writer.WriteNumber(nameof(Character.EvadeRate), value.EvadeRate);
+ writer.WriteEndObject();
+ }
+
+ }
+}
diff --git a/Library/Common/JsonConverter/RoomConverter.cs b/Library/Common/JsonConverter/RoomConverter.cs
index 3d7f263..fa91bf7 100644
--- a/Library/Common/JsonConverter/RoomConverter.cs
+++ b/Library/Common/JsonConverter/RoomConverter.cs
@@ -1,84 +1,60 @@
using System.Text.Json;
-using System.Text.Json.Serialization;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
+using Milimoe.FunGame.Core.Library.Common.Architecture;
using Milimoe.FunGame.Core.Library.SQLScript.Entity;
namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
{
- public class RoomConverter : JsonConverter
+ public class RoomConverter : BaseEntityConverter
{
- public override bool CanConvert(Type objectType)
+ public override Room NewInstance()
{
- return objectType == typeof(Room);
+ return Factory.GetRoom();
}
- public override Room Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
+ public override void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref Room result)
{
- Room room = Factory.GetRoom();
-
- while (reader.Read())
+ switch (propertyName)
{
- if (reader.TokenType == JsonTokenType.EndObject) break;
-
- if (reader.TokenType == JsonTokenType.PropertyName)
- {
- string property = reader.GetString() ?? "";
- reader.Read();
- switch (property)
+ case RoomQuery.Column_ID:
+ result.Id = reader.GetInt64();
+ break;
+ case RoomQuery.Column_RoomID:
+ result.Roomid = reader.GetString() ?? "";
+ break;
+ case RoomQuery.Column_CreateTime:
+ string dateString = reader.GetString() ?? "";
+ if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime date))
{
- case RoomQuery.Column_ID:
- room.Id = reader.GetInt64();
- break;
-
- case RoomQuery.Column_RoomID:
- room.Roomid = reader.GetString() ?? "";
- break;
-
- case RoomQuery.Column_CreateTime:
- string dateString = reader.GetString() ?? "";
- if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime result))
- {
- room.CreateTime = result;
- }
- else room.CreateTime = General.DefaultTime;
- break;
-
- case RoomQuery.Column_RoomMaster:
- string master = reader.GetString() ?? "";
- room.RoomMaster = JsonSerializer.Deserialize(master, options) ?? General.UnknownUserInstance;
- break;
-
- case RoomQuery.Column_RoomType:
- room.RoomType = (RoomType)reader.GetInt64();
- break;
-
- case RoomQuery.Column_GameModule:
- room.GameModule = reader.GetString() ?? "";
- break;
-
- case RoomQuery.Column_GameMap:
- room.GameMap = reader.GetString() ?? "";
- break;
-
- case RoomQuery.Column_RoomState:
- room.RoomState = (RoomState)reader.GetInt64();
- break;
-
- case RoomQuery.Column_IsRank:
- room.IsRank = reader.GetBoolean();
- break;
-
- case RoomQuery.Column_Password:
- room.Password = reader.GetString() ?? "";
- break;
+ result.CreateTime = date;
}
-
- }
+ else result.CreateTime = General.DefaultTime;
+ break;
+ case RoomQuery.Column_RoomMaster:
+ string master = reader.GetString() ?? "";
+ result.RoomMaster = JsonSerializer.Deserialize(master, options) ?? General.UnknownUserInstance;
+ break;
+ case RoomQuery.Column_RoomType:
+ result.RoomType = (RoomType)reader.GetInt64();
+ break;
+ case RoomQuery.Column_GameModule:
+ result.GameModule = reader.GetString() ?? "";
+ break;
+ case RoomQuery.Column_GameMap:
+ result.GameMap = reader.GetString() ?? "";
+ break;
+ case RoomQuery.Column_RoomState:
+ result.RoomState = (RoomState)reader.GetInt64();
+ break;
+ case RoomQuery.Column_IsRank:
+ result.IsRank = reader.GetBoolean();
+ break;
+ case RoomQuery.Column_Password:
+ result.Password = reader.GetString() ?? "";
+ break;
}
-
- return room;
}
public override void Write(Utf8JsonWriter writer, Room value, JsonSerializerOptions options)
diff --git a/Library/Common/JsonConverter/UserConverter.cs b/Library/Common/JsonConverter/UserConverter.cs
index ea0416b..5c99064 100644
--- a/Library/Common/JsonConverter/UserConverter.cs
+++ b/Library/Common/JsonConverter/UserConverter.cs
@@ -1,87 +1,73 @@
using System.Text.Json;
-using System.Text.Json.Serialization;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Constant;
+using Milimoe.FunGame.Core.Library.Common.Architecture;
using Milimoe.FunGame.Core.Library.SQLScript.Entity;
namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
{
- public class UserConverter : JsonConverter
+ public class UserConverter : BaseEntityConverter
{
- public override bool CanConvert(Type objectType)
+ public override User NewInstance()
{
- return objectType == typeof(User);
+ return Factory.GetUser();
}
- public override User Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ public override void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref User result)
{
- User user = Factory.GetUser();
-
- while (reader.Read())
+ switch (propertyName)
{
- if (reader.TokenType == JsonTokenType.EndObject) break;
-
- if (reader.TokenType == JsonTokenType.PropertyName)
- {
- string propertyName = reader.GetString() ?? "";
- reader.Read();
- switch (propertyName)
+ case UserQuery.Column_UID:
+ result.Id = reader.GetInt64();
+ break;
+ case UserQuery.Column_Username:
+ result.Username = reader.GetString() ?? "";
+ break;
+ case UserQuery.Column_RegTime:
+ string regTime = reader.GetString() ?? "";
+ if (DateTime.TryParseExact(regTime, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime RegTime))
{
- case UserQuery.Column_UID:
- user.Id = reader.GetInt64();
- break;
- case UserQuery.Column_Username:
- user.Username = reader.GetString() ?? "";
- break;
- case UserQuery.Column_RegTime:
- string regTime = reader.GetString() ?? "";
- if (DateTime.TryParseExact(regTime, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime RegTime))
- {
- user.RegTime = RegTime;
- }
- else user.RegTime = General.DefaultTime;
- break;
- case UserQuery.Column_LastTime:
- string lastTime = reader.GetString() ?? "";
- if (DateTime.TryParseExact(lastTime, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime LastTime))
- {
- user.LastTime = LastTime;
- }
- else user.LastTime = General.DefaultTime;
- break;
- case UserQuery.Column_Email:
- user.Email = reader.GetString() ?? "";
- break;
- case UserQuery.Column_Nickname:
- user.NickName = reader.GetString() ?? "";
- break;
- case UserQuery.Column_IsAdmin:
- user.IsAdmin = reader.GetBoolean();
- break;
- case UserQuery.Column_IsOperator:
- user.IsOperator = reader.GetBoolean();
- break;
- case UserQuery.Column_IsEnable:
- user.IsEnable = reader.GetBoolean();
- break;
- case UserQuery.Column_Credits:
- user.Credits = reader.GetDecimal();
- break;
- case UserQuery.Column_Materials:
- user.Materials = reader.GetDecimal();
- break;
- case UserQuery.Column_GameTime:
- user.GameTime = reader.GetDecimal();
- break;
- case UserQuery.Column_AutoKey:
- user.AutoKey = reader.GetString() ?? "";
- break;
+ result.RegTime = RegTime;
}
- }
+ else result.RegTime = General.DefaultTime;
+ break;
+ case UserQuery.Column_LastTime:
+ string lastTime = reader.GetString() ?? "";
+ if (DateTime.TryParseExact(lastTime, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime LastTime))
+ {
+ result.LastTime = LastTime;
+ }
+ else result.LastTime = General.DefaultTime;
+ break;
+ case UserQuery.Column_Email:
+ result.Email = reader.GetString() ?? "";
+ break;
+ case UserQuery.Column_Nickname:
+ result.NickName = reader.GetString() ?? "";
+ break;
+ case UserQuery.Column_IsAdmin:
+ result.IsAdmin = reader.GetBoolean();
+ break;
+ case UserQuery.Column_IsOperator:
+ result.IsOperator = reader.GetBoolean();
+ break;
+ case UserQuery.Column_IsEnable:
+ result.IsEnable = reader.GetBoolean();
+ break;
+ case UserQuery.Column_Credits:
+ result.Credits = reader.GetDecimal();
+ break;
+ case UserQuery.Column_Materials:
+ result.Materials = reader.GetDecimal();
+ break;
+ case UserQuery.Column_GameTime:
+ result.GameTime = reader.GetDecimal();
+ break;
+ case UserQuery.Column_AutoKey:
+ result.AutoKey = reader.GetString() ?? "";
+ break;
}
-
- return user;
}
public override void Write(Utf8JsonWriter writer, User value, JsonSerializerOptions options)
diff --git a/Library/Constant/TypeEnum.cs b/Library/Constant/TypeEnum.cs
index 1506cbf..9dec197 100644
--- a/Library/Constant/TypeEnum.cs
+++ b/Library/Constant/TypeEnum.cs
@@ -292,10 +292,10 @@ namespace Milimoe.FunGame.Core.Library.Constant
public enum RoleType
{
Core,
- Guardian,
Vanguard,
- Logistics,
- Assistant
+ Guardian,
+ Support,
+ Medic
}
public enum RoleRating
diff --git a/Service/JsonManager.cs b/Service/JsonManager.cs
index 23c3f8e..fddef52 100644
--- a/Service/JsonManager.cs
+++ b/Service/JsonManager.cs
@@ -18,7 +18,8 @@ namespace Milimoe.FunGame.Core.Service
WriteIndented = true,
Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
ReferenceHandler = ReferenceHandler.IgnoreCycles,
- Converters = { new DateTimeConverter(), new DataTableConverter(), new DataSetConverter(), new UserConverter(), new RoomConverter() }
+ Converters = { new DateTimeConverter(), new DataTableConverter(), new DataSetConverter(), new UserConverter(), new RoomConverter(),
+ new CharacterConverter() }
};
///