I have an API who takes any JSON and I want to make a Excel with it. I'm using
Json.Decode(json)
for convert that JSON in a dynamic object, but I don't know how to access to any key and value created by the decoder.
How can I reference each key and value created?
My code:
Request model
/// <summary>
/// Request de servicio Excel
/// </summary>
public class GenerarExcelRequest
{
/// <summary>
/// Lista de elementos
/// </summary>
public string NombreArchivo { get; set; }
/// <summary>
/// JSON a convertir en Excel
/// </summary>
public object Modelo { get; set; }
}
Service
public GenerarExcelResponse GenerarExcel(GenerarExcelRequest request)
{
using (ExcelPackage exc = new ExcelPackage())
{
ExcelWorksheet ex = exc.Workbook.Worksheets.Add("Reporte Excel");
// If the dynamic object != null, convert it
var modeloDecode = request.Modelo != null ? request.Modelo = Json.Decode(request.Modelo.ToString()) : null;
// I get every value and key created and make the key header of the Excel
if (modeloDecode == null)
return new GenerarExcelResponse() { RutaArchivoExcel = ""};
//var listaEncabezados =
// Load every value in the Excel
// Return the file path of the new Excel
string filePath = "C:\\" + request.NombreArchivo;
byte[] bin = exc.GetAsByteArray();
File.WriteAllBytes(filePath, bin);
return new GenerarExcelResponse()
{
RutaArchivoExcel = filePath
};
}
}
JSON Input Example:
{
"NombreArchivo": "Prueba",
"Modelo": [
{
"id": 24135,
"nombre": "Ignacio"
},
{
"id": 28733,
"nombre": "Francisco"
}
]
}
Excel Output I want
Id ---------- Nombre
24135 ------- Ignacio
28733 ------- Francisco
But the next time that someone use this API may send this input:
JSON Input Example 2:
{
"NombreArchivo": "Prueba2",
"Modelo": [
{
"id": 25,
"product": "XXAA2121",
"stock": 21
},
{
"id": 23,
"product": "XXFJJ212"
"stock": 4
}
]
}
And want to make and Excel like this:
Excel Output I want
Id ---------- Product --------- Stock
25 ---------- XXAA2121 -------- 21
23 ---------- XXFJJ212 -------- 4
I'm not exactly sure what you want, if this should work regardless of the structure of the doc, but something like this might do what you need to get it into a flat list. From there, its a trivial matter to put it into excel. This is a working example from Linqpad once you add Json.NET as a nuget package.
void Main()
{
var jsonFoo = #"{
""NombreArchivo"": ""Prueba"",
""Modelo"": [
{
""id"": 24135,
""nombre"": ""Ignacio""
},
{
""id"": 28733,
""nombre"": ""Francisco""
}
]
}";
var foo = (JObject)JsonConvert.DeserializeObject(jsonFoo);
foo.Dump();
var dict = new List<Tuple<string,string>>();
ConvertJsonToDictionary(foo, dict);
dict.Dump();
}
// Define other methods and classes here
public void ConvertJsonToDictionary(JToken foo, List<Tuple<string,string>> dict)
{
switch(foo.Type)
{
case JTokenType.Object:
foreach (var item in (JObject)foo)
{
dict.Add(new Tuple<string,string>(item.Key, item.Value.ToString()));
if (item.Value.GetType() == typeof(JArray))
{
ConvertJsonToDictionary(item.Value, dict);
}
}
break;
case JTokenType.Array:
foreach(var item in (JArray)foo)
{
ConvertJsonToDictionary(item, dict);
}
break;
}
}
Related
This time I am needing some help deserializing some data that comes from a Web API using using System.Text.Json. After searching all over the place I had found nothing that can really help me solving this issue
Here is a sample of the data:
For the UF Indicator:
{
"UFs": [
{
"Valor": "30.008,40",
"Fecha": "2021-09-10"
}
]
}
For USD Indicator:
{
"Dolares": [
{
"Valor": "791,28",
"Fecha": "2021-09-10"
}
]
}
For UTM Indicator:
{
"UTMs": [
{
"Valor": "52.631",
"Fecha": "2021-09-01"
}
]
}
And a sample for USD with multiple sets of data:
{
"Dolares": [
{
"Valor": "767,10",
"Fecha": "2021-09-02"
},
{
"Valor": "768,36",
"Fecha": "2021-09-03"
},
{
"Valor": "766,53",
"Fecha": "2021-09-06"
},
{
"Valor": "770,33",
"Fecha": "2021-09-07"
},
{
"Valor": "777,94",
"Fecha": "2021-09-08"
},
{
"Valor": "787,51",
"Fecha": "2021-09-09"
},
{
"Valor": "791,28",
"Fecha": "2021-09-10"
}
]
}
This is the class I need to Deserialize to:
public class Indicador : IIndicador
{
public string Valor { get; set; }
public string Fecha { get; set; }
}
The issue starts when I try to Deserialize using this:
var dataFromApi = await httpResponse.Content.ReadAsStringAsync();
var indicador = JsonSerializer.Deserialize<Indicador>(dataFromApi);
I also tried using this "solution" but with no luck at all:
var dataFromApi = await httpResponse.Content.ReadAsStringAsync();
var indicador = JsonSerializer.Deserialize<Dictionary<string,List<indicador>>>(dataFromApi);
So far the only solution has been to create a "container" class that can help me handle that odd "UFs" as a list, since this WebAPI can return multiple other economics indicators than "UFs" which can change to a lot of other concepts, is there a way to map what ever comes from the WebAPI to my generic Indicador class?, the idea is to use a simple object when there is just 1 data and an IEnumerable when there are more than one. I need to stop the dependency for each type of indicator available.
Concerns / Areas of Improvement
Your final paragraph is a little vague and you don't have anymore examples. As such the answer might not be quite as specific as you are looking for.
multiple other economics indicators than "UFs"
Would be nice to see some other examples.
map what ever comes from the WebAPI to my generic Indicador class
Potentially possible, but it remains to be seen how the other data is structured.
Simplest Example
I think you are missing this part of the deserialization process
List<Indicador> indicadors = dataDict["UFs"]; // <-- Will fail If "UFs" is not present
Below is a top level C# program to how to deserialize the given data to a List<Indicador>.
using System;
using System.Text.Json;
using System.Collections.Generic;
// test data
string dataFromApi = #"{
""UFs"": [
{
""Valor"": ""30.008,40"",
""Fecha"": ""2021-09-10""
},
{
""Valor"": ""40.008,50"",
""Fecha"": ""2021-10-10""
}
]
}";
var dataDict = JsonSerializer.Deserialize<Dictionary<string, List<Indicador>>>(dataFromApi);
List<Indicador> indicadors = dataDict["UFs"]; // <-- Will fail If "UFs" is not present
// print out the indicadors
indicadors.ForEach(indicador => Console.WriteLine(indicador));
// Using records because they are brief and come with a good default ToString() method
// You can use regular class if you require
public abstract record IIndicador(string Valor, string Fecha);
public record Indicador(string Valor, string Fecha): IIndicador(Valor, Fecha);
The output of the above top level C# program
Indicador { Valor = 30.008,40, Fecha = 2021-09-10 }
Indicador { Valor = 40.008,50, Fecha = 2021-10-10 }
If "UFs" key is not guaranteed then you can use one of the Dictionary methods to determine if the key is present. For example
if (dataDict.ContainsKey("UFs")) ...
Speculation
Going out on a limb here trying to address some of the aspects of your last paragraph. (You will need to clarify if this address all your concerns and adapt to meet your needs) System.Text.Json also has JsonConverterFactory and JsonConverter<T> for more advanced Conversion requirements should you need them.
using System;
using System.Linq;
using System.Text.Json;
using System.Collections.Generic;
// test data
string multiDataFromApi = #"{
""UFs"": [
{
""Valor"": ""30.008,40"",
""Fecha"": ""2021-09-10""
},
{
""Valor"": ""40.008,50"",
""Fecha"": ""2021-10-10""
}
],
""UFOs"": [
{
""Valor"": ""30.008,40"",
""Fecha"": ""2021-09-10""
}
]
}";
string singleDataFromApi = #"{
""UFs"": [
{
""Valor"": ""30.008,40"",
""Fecha"": ""2021-09-10""
},
{
""Valor"": ""40.008,50"",
""Fecha"": ""2021-10-10""
}
]
}";
processDataFromApi(multiDataFromApi);
processDataFromApi(singleDataFromApi);
void processDataFromApi(string json)
{
var dataDict = JsonSerializer.Deserialize<Dictionary<string, List<Indicador>>>(json);
if (dataDict.Count == 1)
{
Console.WriteLine("-- Single Key Processing --");
List<Indicador> indicadors = dataDict.Values.First();
indicadors.ForEach(indicador => Console.WriteLine("\t{0}", indicador));
}
else
{
Console.WriteLine("-- Multi Key Processing --");
foreach (var keyValuePair in dataDict)
{
Console.WriteLine($"Processing Key: {keyValuePair.Key}");
List<Indicador> indicadors = keyValuePair.Value;
indicadors.ForEach(indicador => Console.WriteLine("\t{0}",indicador));
}
}
Console.WriteLine("-----------------------------");
}
// Using records because they are brief and come with a good default ToString() method
// You can use regular class if you require
public abstract record IIndicador(string Valor, string Fecha);
public record Indicador(string Valor, string Fecha): IIndicador(Valor, Fecha);
which will produce the following output
-- Multi Key Processing --
Processing Key: UFs
Indicador { Valor = 30.008,40, Fecha = 2021-09-10 }
Indicador { Valor = 40.008,50, Fecha = 2021-10-10 }
Processing Key: UFOs
Indicador { Valor = 30.008,40, Fecha = 2021-09-10 }
-----------------------------
-- Single Key Processing --
Indicador { Valor = 30.008,40, Fecha = 2021-09-10 }
Indicador { Valor = 40.008,50, Fecha = 2021-10-10 }
-----------------------------
I have an established JObject object. Trying to loop through it to acquire a Key/value based on anothers Key/value (example of json below with code currently stuck on)
For a tad more detail - looking to loop through "value", get the "KeyID" based on "MailState"
definitely feel like I am missing the step of filtering by MailState/ColName apparently - I have searched through threads a bunch but if someone knows of one that answered this that i was unable to find i will happily pull this down/reference it
// JSON DATA
{
"odata.metadata": "https://..com/odata/$metadata#JCJMCDXes",
"value": [
{
"KeyID": "10379",
"MailCity": "Chicago",
"MailState": "IL"
},
{
"KeyID": "9846",
"MailCity": "Chicago",
"MailState": "IL"
},
{
"KeyID": "2234",
"MailCity": "Madison",
"MailState": "WI"
}]
}
// Current code example
// class in play
public class datastorage
{
public string ID { get; set; }
public string Col { get; set; }
}
public class listData
{
public string ColName {get;set;}
}
// getVPData is a string response from a call to an API
getVPData.Replace(System.Environment.NewLine, "");
JObject jobj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(getVPData);
List<datastorage> data = new List<datastorage>();
// Loop
foreach(var r in listData) // has distinct State abeviations so only 1 occurence
{
foreach (var j in jobj) // This the right path?
{
//add KeyID into ID
data.add(new datastorage
{
ID = ,//add KeyID into ID
Col = r.ColName
});
}
}
You can use Newtonsoft.Json library to parse and loop to the items of value
here is a sample code:
dynamic json = JsonConvert.DeserializeObject(getVPData);
foreach (dynamic item in json["value"])
{
//you can access the fields inside value.
var KeyID = item["KeyID"];
var MailCity = item["MailCity"];
var MailState = item["MailState"];
//just for showing...
Console.WriteLine("KeyID:{0}, MailCity:{1}, MailState:{2}", KeyID, MailCity, MailState);
}
Let me know if the snippet works.
Straightforward ways are:
using System;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ConsoleApp7
{
internal class Program
{
private static void Main(string[] args)
{
var mailStates = new[] {"IL", "WI"};
var jObject = (JObject) JsonConvert.DeserializeObject(json);
var values = (JArray) jObject["value"];
// 1st way
foreach (var mailState in mailStates)
{
var key = values
.Where(v => mailState == v.SelectToken("MailState").Value<string>())
.Select(v => v.Value<string>("KeyID"))
.FirstOrDefault();
Console.WriteLine($"1st case: {mailState} - {key}");
}
/* 2nd way based on JSONPath
* api: https://www.newtonsoft.com/json/help/html/QueryJsonSelectTokenJsonPath.htm
* dox: https://support.smartbear.com/alertsite/docs/monitors/api/endpoint/jsonpath.html
* tester: https://jsonpath.curiousconcept.com/
*/
foreach (var mailState in mailStates)
{
var key = values.SelectTokens($"$[?(#.MailState == '{mailState}')].KeyID")
.Select(v => v.ToString())
.FirstOrDefault();
Console.WriteLine($"2nd case: {mailState} - {key}");
}
Console.ReadKey();
}
private static string json = #"
{
""odata.metadata"": ""https://cdxapiclient.palmercg.com/odata/$metadata#JCJMCDXes"",
""value"": [
{
""KeyID"": ""10379"",
""MailCity"": ""Chicago"",
""MailState"": ""IL""
},
{
""KeyID"": ""9846"",
""MailCity"": ""Chicago"",
""MailState"": ""IL""
},
{
""KeyID"": ""2234"",
""MailCity"": ""Madison"",
""MailState"": ""WI""
}]
}";
}
}
I am trying to print values from a Json string in a gridview with C# using Visual Studio 2017. The problem is that I can't get the specific Value to a single word.
Here is my code:
string link = #"http://alexander.*************/test.php";
string json = new WebClient().DownloadString(link);
JObject jObject = JObject.Parse(json);
I want to print both Values from "Name" in the gridview, but how?
The Names has to put in this Item list:
myItems = (array?);
string test2 = test1.ToString(Formatting.Indented);
ArrayAdapter<string> adapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, myItems);
GridviewCoins.Adapter = adapter;
And finally the json string is:
{
"Coins": [[{
"Name": "007",
"Id": "5294",
}], [{
"Name": "1337",
"Id": "20824",
}
There is a couple problems here, first is that your Coins Property is an array of arrays, and that you jsonObject is not complete it should look like :
"{ "Coins": [[{ "Name": "007", "Id": "5294", } ], [{ "Name": "1337", "Id": "20824", }]]}";
That said if this is a copy paste error I would do some thing like:
public IEnumerable<Coin> GetCoins(string json)
{
var jObject = JObject.Parse(json);
var coinPropery = jObject["Coins"] as JArray;
var coins = new List<Coin>();
foreach (var property in coinPropery)
{
var propertyList = JsonConvert.DeserializeObject<List<Coin>>(property.ToString());
coins.AddRange(propertyList);
}
return coins;
}
and the coin object:
public class Coin
{
public int Id { get; set; }
public string Name { get; set; }
}
when then you have a c# object and you can do what ever you want with it.
EDIT:
You can add to gridview by following Click here
Part of my code serializes file paths of a machine into JSON in the below format. I am struggling to take this JSON and put the file paths back together again. I am using Newtonsoft JSON lib; I find it's excellent for building JSON. As you can see, my JSON has nested objects.
The JSON I have:
{
".": {
"proc": {
"15": {
"task": {
"15": {
"exe": {},
"mounts": {
"list_of_files": [
"mounts.xml"
]
},
"mountinfo": {
"list_of_files": [
"mountinfo.xml"
]
},
"clear_refs": {
"list_of_files": [
"clear_ref.xml"
]
}
}
}
},
"14": {
"loginuid": {
"list_of_files": [
"loginuid.xml"
]
},
"sessionid": {
"list_of_files": [
"sessionid.xml"
]
},
"coredump_filter": {
"list_of_files": [
"coredump_filter.xml"
]
},
"io": {
"list_of_files": [
"io.xml"
]
}
}
}
}
}
The array I want to generate from this.
string[] dirArray = {
"./proc/15/task/15/exe",
"./proc/15/task/15/mounts/mounts.xml",
"./proc/15/task/15/mountinfo/mountinfo.xml",
"./proc/15/task/15/clear_refs/clear_ref.xml",
"./proc/14/loginuid/loginuid.xml",
"./proc/14/sessionid/sessionid.xml",
"./proc/14/coredump_filter/coredump_filter.xml",
"./proc/14/io/io.xml"
}
My efforts so far-- I deserialised the JSON into a dynamic variable but I'm not sure how to handle two issues:
My JSON format is unknown, I don't know how deep the objects go, how can I handle this?
How do I work with dynamic variables when they are defined at run-time?
EDIT
Sorry, my original JSON format was wrong, so it doesn't work with the answer provided by user12864. I'm getting an error: Unable to cast object of type 'Newtonsoft.Json.Linq.JArray' to type 'Newtonsoft.Json.Linq.JObject'.
Here is a fiddle showing where I'm at so far.
#user12864 has the right idea in his answer, but the code needs to be adjusted to account for the fact that each directory can have an array of files rather a single "file" object (you really should have mentioned that in your question originally). Here is an updated method to handle that:
private static void AddToFileList(JObject jo, List<string> list, string prefix)
{
foreach (var kvp in jo)
{
if (kvp.Key == "list_of_files")
{
foreach (string name in (JArray)kvp.Value)
{
list.Add(prefix + name);
}
}
else
{
JObject dir = (JObject)kvp.Value;
if (dir.Count == 0)
{
list.Add(prefix + kvp.Key);
}
else
{
AddToFileList(dir, list, prefix + kvp.Key + "/");
}
}
}
}
Full demo:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
class Program
{
static void Main(string[] args)
{
string json = #"
{
""."": {
""proc"": {
""15"": {
""task"": {
""15"": {
""exe"": {},
""mounts"": {
""list_of_files"": [
""mounts.xml""
]
},
""mountinfo"": {
""list_of_files"": [
""mountinfo.xml""
]
},
""clear_refs"": {
""list_of_files"": [
""clear_ref.xml""
]
}
}
}
},
""14"": {
""loginuid"": {
""list_of_files"": [
""loginuid.xml""
]
},
""sessionid"": {
""list_of_files"": [
""sessionid.xml""
]
},
""coredump_filter"": {
""list_of_files"": [
""coredump_filter.xml""
]
},
""io"": {
""list_of_files"": [
""io.xml""
]
}
}
}
}
}";
JObject jo = JObject.Parse(json);
foreach (string path in CreateFileList(jo))
{
Console.WriteLine(path);
}
}
private static List<string> CreateFileList(JObject jo)
{
List<string> ret = new List<string>();
AddToFileList(jo, ret, "");
return ret;
}
private static void AddToFileList(JObject jo, List<string> list, string prefix)
{
foreach (var kvp in jo)
{
if (kvp.Key == "list_of_files")
{
foreach (string name in (JArray)kvp.Value)
{
list.Add(prefix + name);
}
}
else
{
JObject dir = (JObject)kvp.Value;
if (dir.Count == 0)
{
list.Add(prefix + kvp.Key);
}
else
{
AddToFileList(dir, list, prefix + kvp.Key + "/");
}
}
}
}
}
Output:
./proc/15/task/15/exe
./proc/15/task/15/mounts/mounts.xml
./proc/15/task/15/mountinfo/mountinfo.xml
./proc/15/task/15/clear_refs/clear_ref.xml
./proc/14/loginuid/loginuid.xml
./proc/14/sessionid/sessionid.xml
./proc/14/coredump_filter/coredump_filter.xml
./proc/14/io/io.xml
Fiddle: https://dotnetfiddle.net/r8CkI2
This should give exactly what you're looking for; just create a JObject with JObject.Parse and pass it to CreateFileList. It won't handle malformed JSON in any nice way.
static List<string> CreateFileList(JObject j)
{
List<string> ret = new List<string>();
AddToFileList(j, ret, "");
return ret;
}
static void AddToFileList(JObject j, List<string> dest, string prefix)
{
if (prefix.Length != 0)
prefix = prefix + '/';
foreach (var kvp in j)
{
var jnext = (JObject)kvp.Value;
if (kvp.Key == "file")
dest.Add(prefix + (string)jnext["name"]);
else
AddToFileList(jnext, dest, prefix + kvp.Key);
}
}
Fiddle at https://dotnetfiddle.net/dQQ4tI
Update:
Here is a revised answer, after you clarified your requirement of:
The JavaScript Object Notation is built on the server, edited by user through a hierarchical tree interface component. That can be crawled incredibly easy.
So in essence your utilizing a component, in which your hoping to build simple JavaScript Object Notation derived from the component. Your User Interface will be unknown, so I'll make some presumptions.
Build our Object:
public class XmlPath
{
public string Location { get; set; }
}
The XmlPath will represent our object. Which will be basic auto property.
Add Content to our Object:
private List<XmlPath> AddXmlPath(List<string> location)
{
List<XmlPath> content = new List<XmlPath>();
foreach(string item in location)
content.Add(new XmlPath() { Location = item });
return content;
}
This will be incredibly simple method, it will take a large List<string> of your user data and add them to your XmlPath object.
Remove content from our Object:
private List<XmlPath> RemoveXmlPath(List<XmlPath> root, string location)
{
root.Remove(new XmlPath() { Location = location });
return root;
}
Those two methods truly don't need to be, I'm just demonstrating and showing how you could. Plus it will outline the intentions a bit easier for you to implement. Please note this is incredibly crude approach.
Serialize / Deserialize Our Object to JavaScript Objection Notation:
JavaScriptSerializer serializer = new JavaScriptSerializer();
var xmlPath = AddXmlPath(List<string> location);
var result = serializer.Serialize(xmlPath);
var deserialize = serializer.Deserialize(List<XmlPath>>(result);
Our content is exposed now through a basic loop:
foreach(XmlPath item in deserialize)
{
// Exposed Model via 'item.Location'
}
You'll simply need to correlate this core functionality to your implementation. The approach is crude, quite rudimentary, definitely will need to be improved on for production. However this should get you started with:
Serialize data on the server.
Deserialize server data.
Manipulating the object.
Hope this is better for you.
From a web service method I am returning an object of type 'GridBindingDataSet'. But its not getting serialized as JSON automatically.
Is there some way of making sure that the object gets serialized as JSON? I am using AJAX enabled web service that can be called from client-side using jQuery.
public class GridBindingDataSet
{
public int TotalCount { get; set; }
public DataTable Data { get; set; }
}
EDIT 1:
I am getting the following error when the web service method is called from jQuery:
A circular reference was detected while serializing an object of type 'System.Reflection.RuntimeModule'
EDIT 2:
I used JSON.net to serialize the above object of GridBindingDataSet. The web service is now returning a string rather than a GridBindingObject. Code for this is as below. But the browser cannot understand d.TotalCount and d.Data even though they are there in JSON returned.
[WebMethod]
public string GetJSONDataSetForGrid()
{
...
...
DataTable dt = GetDataForPage0();
int total = GetTotalCount();
GridBindingDataSet gridBindingData = new GridBindingDataSet ( total, dt);
//return a JSON serialized string
return JsonConvert.SerializeObject(gridBindingData,
Formatting.None, new JsonSerializerSettings
{
PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None
});
}
But the JSON being returned is full of back slashes which the browser is not interpreting since the grid using the JSON string is showing up as empty. d.Data and d.TotalCount are not being parsed from the JSON string.
JSON retuned is as below:
{"d":"{\"TotalCount\":81,\"Data\":[{\"ProductName\":\"Alice Mutton\",\"UnitPrice\":39.00,
\"UnitsInStock\":0,\"Discontinued\":true},{\"ProductName\":\"Aniseed Syrup\",\"UnitPrice\":10.00,
\"UnitsInStock\":13,\"Discontinued\":false}]}"}
Also its worth having a look at Json.Net, many would say one of the best Json serializers available, I use it for all of my projects.
In response to the circular referece have a look at preserving references in the documentation, from their examples:
Directory root = new Directory { Name = "Root" };
Directory documents = new Directory { Name = "My Documents", Parent = root };
File file = new File { Name = "ImportantLegalDocument.docx", Parent = documents };
documents.Files = new List<File> { file };
string preserveReferenacesObjects = JsonConvert.SerializeObject(documents, Formatting.Indented, new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
// {
// "$id": "1",
// "Name": "My Documents",
// "Parent": {
// "$id": "2",
// "Name": "Root",
// "Parent": null,
// "Files": null
// },
// "Files": [
// {
// "$id": "3",
// "Name": "ImportantLegalDocument.docx",
// "Parent": {
// "$ref": "1"
// }
// }
// ]
// }