. Net JSON serialization Hands-on tutorial

Source: Internet
Author: User
Tags datetime soap net serialization object serialization serialization

In. NET development, there are two main ways to serialize Json strings in the current mainstream: JavaScriptSerializer and Json.NET (NuGet identity: Newtonsoft.json). JavaScriptSerializer is a method provided by Microsoft, so if you're using asp.net mvc, if you're returning a statement that says "return Json (XXX)" In the action, In fact, you are using the JavaScriptSerializer way. Now more people are choosing json.net, because it provides users with a clearer use of the experience, where is the clarity? This article is mainly to take you into their world.


JavaScriptSerializer and Json.NET

Serialization of

Let's first define a test simple class--person:

public class person
{public
string Name;  public
int age;  Public
Guid Tokenid {get; set;}  Public
DateTime Regtime;  public person child
;  public person
Friend;
}


The members in a class are used only to differentiate between different variable types. We serialize each with JavaScriptSerializer and json.net:

var person = new person   {       age = 28 ,       Name =  "Li Yubao <yubaolee:>",//intentionally add special characters         RegTime = DateTime.Now,       TokenId =  Guid.NewGuid (),       Child = new Person        {           Age = 1,            Name =  "Baby",            RegTime = DateTime.Now,            tokenid = guid.newguid ()        }  };  // Note that the friend here is not assigned a value, the default is null                Javascriptserializer serializeR = new javascriptserializer ();       var jsstr =  Serializer. Serialize (person);                 //using JavaScriptSerializer serialization        string newtonstr =  Jsonconvert.serializeobject (person);   //using json.net serialization


JavaScriptSerializer serialization is an object and then calls its member function serialize for serialization;

Json.NET is serialized directly using the provided static member Jsonconvert.serializeobject;

Both use is relatively simple, json.net call up to facilitate so a lost! Let's take a look at the console output:


The above green for JavaScriptSerializer results, the following yellow background for the results of json.net, here need to pay attention to several places:

1. JavaScriptSerializer Serialized time Format: "\/date (1441813200214) \/" represents the total number of milliseconds from January 1, 1970 (the minimum datetime value) to the date actually represented by date. Usually we need to turn it into a standard time format. You can do string processing in the following ways:

Jsstr = Regex.Replace (Jsstr, @ "\\/date\ ((\d+) \) \\/", match =>
{
datetime dt = new DateTime (1970, 1, 1);
dt = dt. Addmilliseconds (Long. Parse (match. GROUPS[1].  Value));
dt = dt.  ToLocalTime (); return
dt.  ToString ("Yyyy-mm-dd HH:mm:ss");
});


The effect after the process is completed:

Of course, you can also use the inherited JavaScriptConverter method, which is specifically mentioned in deserialization below.

Json.NET Default generated date is also not convenient for the client to read, you need to deal with the simple:

String newtonstr = Jsonconvert.serializeobject (p, formatting.indented,
new Isodatetimeconverter () {D Atetimeformat = "Yyyy-mm-dd HH:mm:ss"});


2, JavaScriptSerializer serialization will be special characters (such as <>) encoding, such as the above \u003c \u003e, a lot of people see this, the first feeling is too pull eggs, then is a variety of Baidu, how to turn this into a normal " <> ". In fact, you do not have to do anything, this is the standard JS encoding, the front-end will handle the problem on its own. Like what:

<script type= "Text/javascript" >
var str = ' Yubaolee <yubaolee> '
var str2 = ' Yubaolee \u003  cyubaolee\u003e ';  
alert (str = = STR2); The result is true
</script>


As you can see from the above two points, the JavaScriptSerializer serialized JSON string is an easy cause for confusion, and Json.NET does not handle the above two situations at all. So now a lot of people are using json.net, but from the HTML standard point of view, the JavaScriptSerializer serialization results more consistent with the requirements of HTML. However, for operating habits, it is recommended to use Json.NET.


Deserialization

We deserialized the two strings that were successfully serialized on the above two different ways:

Deserializes the JavaScriptSerializer generated string
//Using the JavaScriptSerializer method
var Jsperson = serializer.  Deserialize<person> (JSSTR);  
//Use Json.NET method
var Newtonperson = jsonconvert.deserializeobject<person> (JSSTR);
//The json.net generated string is deserialized with
var jsperson2 = serializer.  Deserialize<person> (NEWTONSTR);
var newtonperson2 = jsonconvert.deserializeobject<person> (NEWTONSTR);


By running, you will find that 4 deserialization code works, not as some predecessors have said, JavaScriptSerializer serialized strings can only be deserialized with it, json.net serialized strings can only be deserialized with json.net.

It is not surprising that the deserialized string above is a program-generated, normal deserialization. But usually the strings we want to deserialize are the strings that the customer submits to the server, they are usually incomplete, or some types of mismatches occur. Like what:

String nochildstr =
"{\ name\": \ "Li Yubao <yubaolee:>\", "+
" \ "age\": "+
" \ "regtime\": \ "2    015-09-11 00:10:48\ "," +
"\" friend\ ": null}";
var jsperson = new JavaScriptSerializer ().  Deserialize<person> (NOCHILDSTR);
var Newtonperson = jsonconvert.deserializeobject<person> (NOCHILDSTR);


Note that in this string, there is no tokenid, no child, and friend is null. Take a look at the results:

Two are smart! The results of the parsing are all the things we want. But what if it's like the following?

String nochildstr =
"{\ name\": \ "Li Yubao <yubaolee:>\", "+
" \ "age\": "+
" \ "regtime\": \ "2  015-09-11 00:10:48\ "," +
"\" friend\ ": null," +
"\" tokenid\ ": null}"; Note that this tokenid is empty.


At run time, the program will make a direct error.


The wrong content is easy to understand, because we have a null assignment to the GUID type, and there must be an error. In the actual project operation process may also appear to a content of empty string to the datetime type, a number to the GUID and other parameters passed by the problem, the key is that we have to deal with them, and not to make the program directly to the error of the crash.

1, there is a javascriptconverter in JavaScriptSerializer to handle these issues, which is used to implement the processing of custom types in JSON serialization. The following code, for example, deals with assigning a null assignment to a GUID:

public&nbsp;class&nbsp;personjsconverter&nbsp;:&nbsp;javascriptconverter&nbsp;&nbsp; {&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;public&nbsp;override&nbsp;object&nbsp;deserialize (idictionary&lt;string,&nbsp;object&gt;&nbsp; Dictionary,&nbsp;type&nbsp;type,&nbsp;javascriptserializer&nbsp;serializer) &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Person&nbsp;person&nbsp;=&nbsp;new&nbsp; Person ();&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;object&nbsp;value&nbsp;= &nbsp;null;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp; (dictionary. TryGetValue ("Tokenid", &nbsp;out&nbsp;value) &nbsp;&amp;&amp;&nbsp;value&nbsp;!=&nbsp;null) &nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;person. tokenid&nbsp;=&nbsp; (Guid) &nbsp;value;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//other fields slightly ... &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;person;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;override&nbsp;IDictionary&lt;string,&nbsp;object&gt;&nbsp; Serialize (object&nbsp;obj,&nbsp;javascriptserializer&nbsp;serializer) &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dictionary&lt;string,&nbsp;object&gt;&nbsp;dic &nbsp;=&nbsp;new&nbsp;Dictionary&lt;string,&nbsp;object&gt; ();&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;var&nbsp;node&nbsp;=&nbsp;obj&nbsp;as&nbsp;Person;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;if&nbsp; (node&nbsp;==&nbsp;null) &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;return&nbsp;null;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp; (! String. IsNullOrEmpty (node. Name) &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dic. ADD ("NaMe ", &nbsp;node. Name);&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//other words Gello ...&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;dic;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;override&nbsp;IEnumerable&lt;Type&gt;&nbsp;SupportedTypes&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;type[]&nbsp;{&nbsp;typeof (person) &nbsp;};&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;}


Then, before deserialization, we register the transformation into the entity object, then execute, and the program is all right:

JavaScriptSerializer serializer = new JavaScriptSerializer ();
Serializer.  Registerconverters (new javascriptconverter[] {new Personjsconverter (),});
var deserialize = serializer. Deserialize<person> (NOCHILDSTR);


2, in the use of json.net, a more elegant way to deal with this problem--jsonconverter, it can handle a specified class member variables. This does not have to do with all the members of the entire class like the javascriptconverter above. The code is as follows:

public&nbsp;class&nbsp;guidconverter&nbsp;:&nbsp;jsonconverter&nbsp;&nbsp; {&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public&nbsp;override&nbsp;bool&nbsp;canconvert (type&nbsp;objecttype) &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;objecttype.isassignablefrom (typeof ( GUID));&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp; Override&nbsp;object&nbsp;readjson (jsonreader&nbsp;reader,&nbsp;type&nbsp;objecttype,&nbsp;object&nbsp; Existingvalue,&nbsp;jsonserializer&nbsp;serializer) &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;serializer.
Deserialize&lt;guid&gt; (reader);&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//if the incoming value causes an exception, an initial value is assigned &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Guid.Empty;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;public&nbsp;override&nbsp;void&nbsp;writejson (Jsonwriter&nbsp;writer,&nbsp;object&nbsp;value, &nbsp;jsonserializer&nbsp;serializer) &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;serializer. Serialize (Writer,&nbsp;value);&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;}


It is worth noting that Jsonconverter is an attribute, so add an attribute to the class member:

public class person
{public
string Name;  public
int age;  
[Jsonconverter (typeof (Guidconverter))] public
Guid Tokenid {get; set;}  Public
DateTime Regtime;  public person child
;  public person
Friend;
}


At this point, the Tokenid will be assigned an initial value when the program is run again. It seems that in the deserialization, the json.net is still better.


Performance

This is a two performance comparison on the Web:


On the other side, without considering the requirement of the system to the third party control reference, we should use Json.NET to do the object serialization processing.


Other common serialization methods

For a long time, review the definition of serialization: Serialization: The process of converting an object into a byte stream, which makes it easy to save an object in a disk file or database.

Deserialization: The reverse process of serialization is the process of swapping byte flows back to the original object.



serialization and deserialization in ASP.net, and JSON serialization deserialization

Serialization is the process of converting an object state into a format that can be persisted or transmitted, and deserialization is the opposite. Used to store and transfer data.

(i) asp.net serialization and deserialization

. NET provides a variety of serialization classes

(1) BinaryFormatter class

Name space: System.Runtime.Serialization.Formatters.Binary

This class is used to serialize and deserialize an object or an entire connection object graph in binary format

Builder Two:
BinaryFormatter ()
BinaryFormatter (Isurrogateselector, StreamingContext)

Describe its two main methods:

1 Serialize method

Serializes an object or Connection object graph into a given stream

It has two overloads:
Serialize (Stream, Object)
Serialize (Stream, object,header[])

Class Customer

public class Customer
{public
int Unid {get; set;}
public string Name {get; set;}
public string Call {get; set;}
}


The following sample is used to test the serialization method serialize

public void testserialize () {    customer
 customer = new customer {unid=1,name= "Song Jiang", call= "89589689"  };     filestream fs = new filestream ("Test.dat",  filemode.create);
      binaryformatter formatter = new binaryformatter ();     try     {        formatter.
Serialize (Fs, customer); &NBSP;&NBSP;&NBSP;&NBSP}     catch     { }      Finally     {        fs. Close (); 

}
}

When testing, this throws an exception: type "Serializetest.customer" is not marked as serializable. So to add a cosmetic label on the customer class

[Serializable]
public class Customer

Test, you can see the Test.dat file in the Bin\Debug folder.

2 Deserialize method

Deserializes a stream into an object graph, which also has two overloads

Deserialize (Stream)
Deserialize (Stream, HeaderHandler)

To test the deserialization of a stream from a sample

public void Testdeserialize ()
{
Customer customer = new Customer ();
FileStream fs = new FileStream ("Test.dat", FileMode.Open);
BinaryFormatter formatter = new BinaryFormatter ();
Customer= Formatter.    Deserialize (FS) as Customer;
Fs.    Close ();
Console.WriteLine (Customer. Name);


Result output: Song Jiang

(2) SoapFormatter class

Namespace: System.Runtime.Serialization.Formatters.Soap

Serializes and deserializes the graphics of an object or an entire connection object in a Soap format.

SOAP is the acronym for Simple Object-access protocol. is a lightweight, simple, xml-based protocol.

The reference to add to the System.Runtime.Serialization.Formatters.Soap.dll

Constructor:

SoapFormatter xx=new  SoapFormatter ()
SoapFormatter (Isurrogateselector, StreamingContext)

mainly describes 2 of these methods

1 Serialize method

Serialize (Stream, object)
Serialize (Stream, object, header[]

public void testsoapserialize () {    customer  customer = new Customer { Unid = 1, Name =  "Song Jiang", 
call =  "89589689"  };     filestream fs = new filestream ("Soaptest.dat", 
FileMode.Create);
    soapformatter formatter = new soapformatter ();     try     {        formatter.
Serialize (Fs, customer); &NBSP;&NBSP;&NBSP;&NBSP}     catch     { }      Finally     {        fs.
Close (); &NBSP;&NBSP;&NBSP;&NBSP}} 


Open the Soaptest.dat file in Bin\Debug, which is the SOAP format.

2 Deserialize method

Deserialization SOAP Format

Deserialize (Stream)
Deserialize (Stream, HeaderHandler)

I don't have much else to say.

public void Testsoapdeserialize ()
{
Customer customer = new Customer ();
FileStream fs = new FileStream ("Soaptest.dat", FileMode.Open);
SoapFormatter formatter = new SoapFormatter ();
Customer = Formatter.    Deserialize (FS) as Customer;
Fs.    Close ();
Console.WriteLine (Customer. Name);


(3) XmlSerializer class

Serializing an object to an XML document and deserializing an object from an XML document

Name space: System.Xml.Serialization

The construction method is too many, does not enumerate, may refer to the Help

1 Serialize method

Come up with one to say:

public void Serialize (XmlWriter xmlwriter,object o) public
void Testxmlserialize ()
{
Customer customer = n    EW Customer {Unid = 1, Name = "Song Jiang", call = "89589689"};
FileStream fs = new FileStream ("Xmltest.xml", FileMode.Create);
XmlSerializer formatter = new XmlSerializer (typeof (Customer));
Formatter.    Serialize (FS, customer);
Fs. Close ();
}


The results can be viewed in debug\bin.

2 Deserialize method

public void testxmldeserialize () {    
Customer customer = new customer ();
    filestream fs = new filestream ("Xmltest.xml",  FileMode.Open);
    xmlserializer formatter = new xmlserializer (typeof (Customer));     customer = formatter.
Deserialize (FS)  as Customer;     fs.
Close ();     console.writeline (Customer.
Name); }


(ii) JSON serialization and deserialization

JSON serialization and deserialization refers to an object serialized as JSON and can be used to deserialize objects from JSON

in. NET 3.5

Namespace: System.Runtime.Serialization.Json

But the assembly is: System.ServiceModel.Web.dll


(1) The DataContractJsonSerializer class

constructs many methods. The

describes 2 methods of this class:

1 writeobject method

has a good overload, here is a test:

public override void WriteObject (Stream stream,object graph)

Test:

public void Testjsonserialize ()
{
Customer customer = new Customer {Unid = 1, Name = "Song Jiang", call = "89589689"    };
DataContractJsonSerializer ds = new DataContractJsonSerializer (typeof (Customer));    
FileStream fs = new FileStream ("Json.txt", FileMode.Create);
Ds.    WriteObject (FS, customer);
Fs. Close ();
}


Type does not have to add cosmetic labels when making JSON serialization

You can see the JSON string in the bin\debug.

2 ReadObject method

Many overloads.

public override Object ReadObject (Stream stream)

Test:


public void Testjsondeserialize ()
{
DataContractJsonSerializer ds =
new Datacontractjsonserialize R (typeof (Customer));    
FileStream fs = new FileStream ("Json.txt", FileMode.Open);
var cc = ds.    ReadObject (FS);
Fs. Close ();
}


(2) JavaScriptSerializer class

Provides serialization and deserialization capabilities for Afax-enabled applications

Name space: System.Web.Script.Serialization

Assembly: System.Web.Extensions (in System.Web.Extensions.dll)

Say 2 of these methods

1 Serialize method

Serialize (Object)
Serialize (Object, StringBuilder)

public void Testjsserialize ()
{
Customer customer = new Customer {Unid = 1, Name = "Song Jiang", call = "89589689"};    
JavaScriptSerializer js = new JavaScriptSerializer ();
Console.WriteLine (JS. Serialize (customer));


Output string: {"Unid": 1, "Name": "Song Jiang", "Call": "89589689"}

2 Deserialize method

public void Testjsdeserialize ()
{
string str = File.readalltext ("Jsjson.txt");
JavaScriptSerializer js = new JavaScriptSerializer ();
Customer customer = js. Deserialize<customer> (str);
Console.WriteLine (Customer. Name);


(3) Json.NET

Name space: Newtonsoft.json

Add Newtonsoft.Json.dll Assembly

2 of these methods:

1 SerializeObject method

public void Testjsonnetserialize ()
{
Customer customer = new Customer {Unid = 1, Name = "Song Jiang", call = "8958968"    9 "};
String Strjson=jsonconvert.serializeobject (customer);
StreamWriter sw = File.createtext ("Jsonnet.txt");
Sw.    Write (Strjson);
Sw. Close ();
}


2 Deserializeobject method

public void Testjsonnetdeserialize ()
{
string str = File.readalltext ("Jsonnet.txt");
Customer customer = jsonconvert.deserializeobject<customer> (str);
Console.WriteLine (Customer. Name);


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.