-Added JsonRequiredProperty

-Added JsonSerializerSettings.ReferenceResolverProvider property
-Marked JsonSerializerSettings.ReferenceResolver as obsolete
This commit is contained in:
James Newton-King
2015-05-02 19:40:44 +12:00
parent 0cc866a445
commit 0f584a6d52
23 changed files with 319 additions and 38 deletions
@@ -57,4 +57,4 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("7.0.0.0")]
[assembly: AssemblyFileVersion("7.0.1.18407")]
[assembly: AssemblyFileVersion("7.0.1.18502")]
@@ -425,7 +425,6 @@ namespace Newtonsoft.Json.Tests.Converters
Assert.AreEqual("item!", pair2.Key.Rows[0]["item"]);
}
[Test]
public void SerializedTypedDataTable()
{
@@ -62,6 +62,7 @@ namespace Newtonsoft.Json.Tests.Documentation.Samples.Linq
};
}
[Test]
public void Example()
{
#region Usage
@@ -41,7 +41,6 @@ namespace Newtonsoft.Json.Tests.Documentation.Samples.Serializer
public class DeserializeImmutableCollections : TestFixtureBase
{
[Test]
[Ignore]
public void Example()
{
#region Usage
@@ -41,7 +41,6 @@ namespace Newtonsoft.Json.Tests.Documentation.Samples.Serializer
public class SerializeImmutableCollections : TestFixtureBase
{
[Test]
[Ignore]
public void Example()
{
#region Usage
@@ -76,4 +76,4 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("7.0.0.0")]
[assembly: AssemblyFileVersion("7.0.1.18407")]
[assembly: AssemblyFileVersion("7.0.1.18502")]
@@ -146,6 +146,161 @@ namespace Newtonsoft.Json.Tests.Serialization
}
#endif
public class RequiredPropertyTestClass
{
[JsonRequired]
internal string Name { get; set; }
}
[Test]
public void RequiredPropertyTest()
{
RequiredPropertyTestClass c1 = new RequiredPropertyTestClass();
ExceptionAssert.Throws<JsonSerializationException>(
() => JsonConvert.SerializeObject(c1),
"Cannot write a null value for property 'Name'. Property requires a value. Path ''.");
RequiredPropertyTestClass c2 = new RequiredPropertyTestClass
{
Name = "Name!"
};
string json = JsonConvert.SerializeObject(c2);
Assert.AreEqual(@"{""Name"":""Name!""}", json);
ExceptionAssert.Throws<JsonSerializationException>(
() => JsonConvert.DeserializeObject<RequiredPropertyTestClass>(@"{}"),
"Required property 'Name' not found in JSON. Path '', line 1, position 2.");
ExceptionAssert.Throws<JsonSerializationException>(
() => JsonConvert.DeserializeObject<RequiredPropertyTestClass>(@"{""Name"":null}"),
"Required property 'Name' expects a value but got null. Path '', line 1, position 13.");
RequiredPropertyTestClass c3 = JsonConvert.DeserializeObject<RequiredPropertyTestClass>(@"{""Name"":""Name!""}");
Assert.AreEqual("Name!", c3.Name);
}
public class RequiredPropertyConstructorTestClass
{
public RequiredPropertyConstructorTestClass(string name)
{
Name = name;
}
[JsonRequired]
internal string Name { get; set; }
}
[Test]
public void RequiredPropertyConstructorTest()
{
RequiredPropertyConstructorTestClass c1 = new RequiredPropertyConstructorTestClass(null);
ExceptionAssert.Throws<JsonSerializationException>(
() => JsonConvert.SerializeObject(c1),
"Cannot write a null value for property 'Name'. Property requires a value. Path ''.");
RequiredPropertyConstructorTestClass c2 = new RequiredPropertyConstructorTestClass("Name!");
string json = JsonConvert.SerializeObject(c2);
Assert.AreEqual(@"{""Name"":""Name!""}", json);
ExceptionAssert.Throws<JsonSerializationException>(
() => JsonConvert.DeserializeObject<RequiredPropertyConstructorTestClass>(@"{}"),
"Required property 'Name' not found in JSON. Path '', line 1, position 2.");
RequiredPropertyConstructorTestClass c3 = JsonConvert.DeserializeObject<RequiredPropertyConstructorTestClass>(@"{""Name"":""Name!""}");
Assert.AreEqual("Name!", c3.Name);
}
public class IgnoredPropertiesTestClass
{
[JsonIgnore]
public Version IgnoredProperty { get; set; }
[JsonIgnore]
public List<Version> IgnoredList { get; set; }
[JsonIgnore]
public Dictionary<string, Version> IgnoredDictionary { get; set; }
[JsonProperty(Required = Required.Always)]
public string Name { get; set; }
}
public class IgnoredPropertiesContractResolver : DefaultContractResolver
{
public override JsonContract ResolveContract(Type type)
{
if (type == typeof(Version))
throw new Exception("Error!");
return base.ResolveContract(type);
}
}
[Test]
public void NeverResolveIgnoredPropertyTypes()
{
Version v = new Version(1, 2, 3, 4);
IgnoredPropertiesTestClass c1 = new IgnoredPropertiesTestClass
{
IgnoredProperty = v,
IgnoredList = new List<Version>
{
v
},
IgnoredDictionary = new Dictionary<string, Version>
{
{ "Value", v }
},
Name = "Name!"
};
string json = JsonConvert.SerializeObject(c1, Formatting.Indented, new JsonSerializerSettings
{
ContractResolver = new IgnoredPropertiesContractResolver()
});
Assert.AreEqual(@"{
""Name"": ""Name!""
}", json);
string deserializeJson = @"{
""IgnoredList"": [
{
""Major"": 1,
""Minor"": 2,
""Build"": 3,
""Revision"": 4,
""MajorRevision"": 0,
""MinorRevision"": 4
}
],
""IgnoredDictionary"": {
""Value"": {
""Major"": 1,
""Minor"": 2,
""Build"": 3,
""Revision"": 4,
""MajorRevision"": 0,
""MinorRevision"": 4
}
},
""Name"": ""Name!""
}";
IgnoredPropertiesTestClass c2 = JsonConvert.DeserializeObject<IgnoredPropertiesTestClass>(deserializeJson, new JsonSerializerSettings
{
ContractResolver = new IgnoredPropertiesContractResolver()
});
Assert.AreEqual("Name!", c2.Name);
}
#if !(NETFX_CORE || DNXCORE50 || NET20)
[MetadataType(typeof(CustomerValidation))]
public partial class CustomerWithMetadataType
@@ -721,8 +876,14 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual(ReferenceLoopHandling.Ignore, settings.ReferenceLoopHandling);
IdReferenceResolver referenceResolver = new IdReferenceResolver();
#pragma warning disable 618
settings.ReferenceResolver = referenceResolver;
Assert.AreEqual(referenceResolver, settings.ReferenceResolver);
#pragma warning restore 618
Assert.AreEqual(referenceResolver, settings.ReferenceResolverProvider());
settings.ReferenceResolverProvider = () => referenceResolver;
Assert.AreEqual(referenceResolver, settings.ReferenceResolverProvider());
settings.StringEscapeHandling = StringEscapeHandling.EscapeNonAscii;
Assert.AreEqual(StringEscapeHandling.EscapeNonAscii, settings.StringEscapeHandling);
@@ -8050,7 +8211,9 @@ Path '', line 1, position 1.");
string json = JsonConvert.SerializeObject(people, new JsonSerializerSettings
{
#pragma warning disable 618
ReferenceResolver = new IdReferenceResolver(),
#pragma warning restore 618
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
Formatting = Formatting.Indented
});
@@ -8112,7 +8275,45 @@ Path '', line 1, position 1.");
IList<PersonReference> people = JsonConvert.DeserializeObject<IList<PersonReference>>(json, new JsonSerializerSettings
{
#pragma warning disable 618
ReferenceResolver = new IdReferenceResolver(),
#pragma warning restore 618
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
Formatting = Formatting.Indented
});
Assert.AreEqual(2, people.Count);
PersonReference john = people[0];
PersonReference jane = people[1];
Assert.AreEqual(john, jane.Spouse);
Assert.AreEqual(jane, john.Spouse);
}
[Test]
public void DeserializeCustomReferenceResolver_ViaProvider()
{
string json = @"[
{
""$id"": ""0b64ffdf-d155-44ad-9689-58d9adb137f3"",
""Name"": ""John Smith"",
""Spouse"": {
""$id"": ""ae3c399c-058d-431d-91b0-a36c266441b9"",
""Name"": ""Jane Smith"",
""Spouse"": {
""$ref"": ""0b64ffdf-d155-44ad-9689-58d9adb137f3""
}
}
},
{
""$ref"": ""ae3c399c-058d-431d-91b0-a36c266441b9""
}
]";
IList<PersonReference> people = JsonConvert.DeserializeObject<IList<PersonReference>>(json, new JsonSerializerSettings
{
ReferenceResolverProvider = () => new IdReferenceResolver(),
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
Formatting = Formatting.Indented
});
@@ -876,7 +876,7 @@ Newtonsoft.Json Error: 0 : Error!
traceWriter.Flush();
traceWriter.Close();
StringAssert.AreEqual(@"{
string json = @"{
""Array"": [
""String!"",
""2000-12-12T12:12:12Z"",
@@ -927,7 +927,9 @@ Newtonsoft.Json Error: 0 : Error!
)
/*A comment*/
]
}", traceWriter.GetJson());
}";
StringAssert.AreEqual("Serialized JSON: " + Environment.NewLine + json, traceWriter.GetSerializedJsonMessage());
}
[Test]
@@ -1035,7 +1037,7 @@ Newtonsoft.Json Error: 0 : Error!
traceReader.Close();
StringAssert.AreEqual(json, traceReader.GetJson());
StringAssert.AreEqual("Deserialized JSON: " + Environment.NewLine + json, traceReader.GetDeserializedJsonMessage());
}
#endif
}
@@ -0,0 +1,39 @@
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
using System.Text;
namespace Newtonsoft.Json
{
/// <summary>
/// Instructs the <see cref="JsonSerializer"/> to always serialize the member, and require the member has a value.
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public sealed class JsonRequiredAttribute : Attribute
{
}
}
+5 -5
View File
@@ -559,8 +559,8 @@ namespace Newtonsoft.Json
if (settings.ContractResolver != null)
serializer.ContractResolver = settings.ContractResolver;
if (settings.ReferenceResolver != null)
serializer.ReferenceResolver = settings.ReferenceResolver;
if (settings.ReferenceResolverProvider != null)
serializer.ReferenceResolver = settings.ReferenceResolverProvider();
if (settings.TraceWriter != null)
serializer.TraceWriter = settings.TraceWriter;
if (settings.Binder != null)
@@ -638,7 +638,7 @@ namespace Newtonsoft.Json
serializerReader.Populate(traceJsonReader ?? reader, target);
if (traceJsonReader != null)
TraceWriter.Trace(TraceLevel.Verbose, "Deserialized JSON: " + Environment.NewLine + traceJsonReader.GetJson(), null);
TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null);
ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString);
}
@@ -710,7 +710,7 @@ namespace Newtonsoft.Json
object value = serializerReader.Deserialize(traceJsonReader ?? reader, objectType, CheckAdditionalContent);
if (traceJsonReader != null)
TraceWriter.Trace(TraceLevel.Verbose, "Deserialized JSON: " + Environment.NewLine + traceJsonReader.GetJson(), null);
TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null);
ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString);
@@ -925,7 +925,7 @@ namespace Newtonsoft.Json
serializerWriter.Serialize(traceJsonWriter ?? jsonWriter, value, objectType);
if (traceJsonWriter != null)
TraceWriter.Trace(TraceLevel.Verbose, "Serialized JSON: " + Environment.NewLine + traceJsonWriter.GetJson(), null);
TraceWriter.Trace(TraceLevel.Verbose, traceJsonWriter.GetSerializedJsonMessage(), null);
// reset writer back to previous options
if (previousFormatting != null)
+17 -1
View File
@@ -203,7 +203,23 @@ namespace Newtonsoft.Json
/// Gets or sets the <see cref="IReferenceResolver"/> used by the serializer when resolving references.
/// </summary>
/// <value>The reference resolver.</value>
public IReferenceResolver ReferenceResolver { get; set; }
[ObsoleteAttribute("ReferenceResolver property is obsolete. Use the ReferenceResolverProvider property to set the IReferenceResolver: settings.ReferenceResolverProvider = () => resolver")]
public IReferenceResolver ReferenceResolver
{
get
{
if (ReferenceResolverProvider == null)
return null;
return ReferenceResolverProvider();
}
set { ReferenceResolverProvider = () => value; }
}
/// <summary>
/// Gets or sets a function that creates the <see cref="IReferenceResolver"/> used by the serializer when resolving references.
/// </summary>
/// <value>A function that creates the <see cref="IReferenceResolver"/> used by the serializer when resolving references.</value>
public Func<IReferenceResolver> ReferenceResolverProvider { get; set; }
/// <summary>
/// Gets or sets the <see cref="ITraceWriter"/> used by the serializer when writing trace messages.
@@ -108,6 +108,7 @@
<Compile Include="JsonException.cs" />
<Compile Include="JsonExtensionDataAttribute.cs" />
<Compile Include="JsonPosition.cs" />
<Compile Include="JsonRequiredAttribute.cs" />
<Compile Include="Linq\JPropertyKeyedCollection.cs" />
<Compile Include="Linq\JsonMergeSettings.cs" />
<Compile Include="Linq\JsonPath\ArrayIndexFilter.cs" />
@@ -120,6 +120,7 @@
<Compile Include="JsonException.cs" />
<Compile Include="JsonExtensionDataAttribute.cs" />
<Compile Include="JsonPosition.cs" />
<Compile Include="JsonRequiredAttribute.cs" />
<Compile Include="Linq\JPropertyDescriptor.cs" />
<Compile Include="Linq\JPropertyKeyedCollection.cs" />
<Compile Include="Linq\JsonMergeSettings.cs" />
@@ -121,6 +121,7 @@
<Compile Include="JsonConstructorAttribute.cs" />
<Compile Include="JsonExtensionDataAttribute.cs" />
<Compile Include="JsonPosition.cs" />
<Compile Include="JsonRequiredAttribute.cs" />
<Compile Include="Linq\JPropertyKeyedCollection.cs" />
<Compile Include="Linq\JsonMergeSettings.cs" />
<Compile Include="Linq\JsonPath\ArrayIndexFilter.cs" />
@@ -94,6 +94,7 @@
<Compile Include="JsonPropertyAttribute.cs" />
<Compile Include="JsonReader.cs" />
<Compile Include="JsonReaderException.cs" />
<Compile Include="JsonRequiredAttribute.cs" />
<Compile Include="JsonSerializationException.cs" />
<Compile Include="JsonSerializer.cs" />
<Compile Include="JsonSerializerSettings.cs" />
@@ -99,6 +99,7 @@
<Compile Include="JsonPropertyAttribute.cs" />
<Compile Include="JsonReader.cs" />
<Compile Include="JsonReaderException.cs" />
<Compile Include="JsonRequiredAttribute.cs" />
<Compile Include="JsonSerializationException.cs" />
<Compile Include="JsonSerializer.cs" />
<Compile Include="JsonSerializerSettings.cs" />
@@ -92,6 +92,7 @@
<Compile Include="JsonDictionaryAttribute.cs" />
<Compile Include="JsonException.cs" />
<Compile Include="JsonExtensionDataAttribute.cs" />
<Compile Include="JsonRequiredAttribute.cs" />
<Compile Include="JsonIgnoreAttribute.cs" />
<Compile Include="JsonObjectAttribute.cs" />
<Compile Include="JsonPosition.cs" />
@@ -92,5 +92,5 @@ using System.Security;
// by using the '*' as shown below:
[assembly: AssemblyVersion("7.0.0.0")]
[assembly: AssemblyFileVersion("7.0.1.18407")]
[assembly: AssemblyFileVersion("7.0.1.18502")]
[assembly: CLSCompliant(true)]
@@ -308,6 +308,8 @@ namespace Newtonsoft.Json.Serialization
// or are a field if serializing just fields
if (JsonTypeReflector.GetAttribute<JsonPropertyAttribute>(member) != null)
serializableMembers.Add(member);
else if (JsonTypeReflector.GetAttribute<JsonRequiredAttribute>(member) != null)
serializableMembers.Add(member);
#if !NET20
else if (dataContractAttribute != null && JsonTypeReflector.GetAttribute<DataMemberAttribute>(member) != null)
serializableMembers.Add(member);
@@ -1222,8 +1224,7 @@ namespace Newtonsoft.Json.Serialization
#endif
JsonPropertyAttribute propertyAttribute = JsonTypeReflector.GetAttribute<JsonPropertyAttribute>(attributeProvider);
if (propertyAttribute != null)
property.HasMemberAttribute = true;
JsonRequiredAttribute requiredAttribute = JsonTypeReflector.GetAttribute<JsonRequiredAttribute>(attributeProvider);
string mappedName;
if (propertyAttribute != null && propertyAttribute.PropertyName != null)
@@ -1255,6 +1256,13 @@ namespace Newtonsoft.Json.Serialization
hasMemberAttribute = true;
}
#endif
if (requiredAttribute != null)
{
property._required = Required.Always;
hasMemberAttribute = true;
}
property.HasMemberAttribute = hasMemberAttribute;
bool hasJsonIgnoreAttribute =
JsonTypeReflector.GetAttribute<JsonIgnoreAttribute>(attributeProvider) != null
@@ -1310,18 +1318,10 @@ namespace Newtonsoft.Json.Serialization
if ((DefaultMembersSearchFlags & BindingFlags.NonPublic) == BindingFlags.NonPublic)
allowNonPublicAccess = true;
#pragma warning restore 618
if (propertyAttribute != null)
if (hasMemberAttribute)
allowNonPublicAccess = true;
if (memberSerialization == MemberSerialization.Fields)
allowNonPublicAccess = true;
#if !NET20
if (dataMemberAttribute != null)
{
allowNonPublicAccess = true;
property.HasMemberAttribute = true;
}
#endif
}
private Predicate<object> CreateShouldSerializeTest(MemberInfo member)
@@ -1958,10 +1958,15 @@ namespace Newtonsoft.Json.Serialization
continue;
}
if (property.PropertyContract == null)
property.PropertyContract = GetContractSafe(property.PropertyType);
JsonConverter propertyConverter = null;
JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter, contract, member);
if (!property.Ignored)
{
if (property.PropertyContract == null)
property.PropertyContract = GetContractSafe(property.PropertyType);
propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter, contract, member);
}
if (!ReadForType(reader, property.PropertyContract, propertyConverter != null))
throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
@@ -2060,11 +2065,14 @@ namespace Newtonsoft.Json.Serialization
if (resolvedRequired == Required.AllowNull || resolvedRequired == Required.Always)
throw JsonSerializationException.Create(reader, "Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName));
if (property.PropertyContract == null)
property.PropertyContract = GetContractSafe(property.PropertyType);
if (!property.Ignored)
{
if (property.PropertyContract == null)
property.PropertyContract = GetContractSafe(property.PropertyType);
if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate) && property.Writable && !property.Ignored)
property.ValueProvider.SetValue(newObject, EnsureType(reader, property.GetResolvedDefaultValue(), CultureInfo.InvariantCulture, property.PropertyContract, property.PropertyType));
if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate) && property.Writable)
property.ValueProvider.SetValue(newObject, EnsureType(reader, property.GetResolvedDefaultValue(), CultureInfo.InvariantCulture, property.PropertyContract, property.PropertyType));
}
break;
case PropertyPresence.Null:
if (resolvedRequired == Required.Always)
@@ -41,12 +41,17 @@ namespace Newtonsoft.Json.Serialization
/// <param name="ex">The trace exception. This parameter is optional.</param>
public void Trace(TraceLevel level, string message, Exception ex)
{
string traceMessage = DateTime.Now.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff", CultureInfo.InvariantCulture) + " " + level.ToString("g") + " " + message;
if (_traceMessages.Count >= 1000)
_traceMessages.Dequeue();
_traceMessages.Enqueue(traceMessage);
StringBuilder sb = new StringBuilder();
sb.Append(DateTime.Now.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff", CultureInfo.InvariantCulture));
sb.Append(" ");
sb.Append(level.ToString("g"));
sb.Append(" ");
sb.Append(message);
_traceMessages.Enqueue(sb.ToString());
}
/// <summary>
@@ -17,11 +17,14 @@ namespace Newtonsoft.Json.Serialization
_innerReader = innerReader;
_sw = new StringWriter(CultureInfo.InvariantCulture);
// prefix the message in the stringwriter to avoid concat with a potentially large JSON string
_sw.Write("Deserialized JSON: " + Environment.NewLine);
_textWriter = new JsonTextWriter(_sw);
_textWriter.Formatting = Formatting.Indented;
}
public string GetJson()
public string GetDeserializedJsonMessage()
{
return _sw.ToString();
}
@@ -20,6 +20,9 @@ namespace Newtonsoft.Json.Serialization
_innerWriter = innerWriter;
_sw = new StringWriter(CultureInfo.InvariantCulture);
// prefix the message in the stringwriter to avoid concat with a potentially large JSON string
_sw.Write("Serialized JSON: " + Environment.NewLine);
_textWriter = new JsonTextWriter(_sw);
_textWriter.Formatting = Formatting.Indented;
_textWriter.Culture = innerWriter.Culture;
@@ -29,7 +32,7 @@ namespace Newtonsoft.Json.Serialization
_textWriter.FloatFormatHandling = innerWriter.FloatFormatHandling;
}
public string GetJson()
public string GetSerializedJsonMessage()
{
return _sw.ToString();
}