sort JSONArray without Gson, Jackson, etc - java

In my app, the class below receives a JSONArray and use its data to populate a ListView. I want the fields in this ListView to appear in an Alphabetical order. So I want to sort my JSONArray before using its data.
I've saw some topics suggesting to use GSON or Jackson, but I'm trying to do this in a simpler way. I don't understand well these libraries and did't find what I need in their tutorials.
An example of the JSON:
{"0":["1","Alimentos e Bebidas","Y"],"1":["6","Beleza e Cosm\u00e9ticos","Y"],"2":
["11","Cama, Mesa e Banho","Y"],"3":["3","CDs, DVDs e Games","Y"],"4":["2","Convites
e Cortesias","Y"],"5":["23","Cursos","Y"],"6":["8","Eletr\u00f4nicos","Y"],"7":
["16","Esporte e Lazer","Y"],"8":["14","Inform\u00e1tica e Acess\u00f3rios","Y"],
"9":["10","Limpeza","Y"],"10":["4","Livros","Y"],"11":["21","Livros no Sebo","Y"],
"12":["5","Outros","Y"],"13":["12","Roupas e Acess\u00f3rios","Y"]}
The class' method where I populate the list and wait for user:
public void proccess(){
listview = (ListView) findViewById(R.id.include3);
int qtdCategorias = json.length();
categorias = new String[qtdCategorias];
itens = new ArrayList<ItemListView>();
for (int i=0; i<qtdCategorias; i++){
c = json.optJSONArray(i);
String nomeCategoria = null;
try {
nomeCategoria = c.getString(1); //A consulta SQL do php retorna somente categorias habilitadas
} catch (JSONException e) {
Log.e("CategoriasShoppingActivity", e.toString());
e.printStackTrace();
}
categorias[i] = nomeCategoria;
//ItemListView item = new ItemListView(nomeCategoria);
//itens.add(item);
}
Arrays.sort(categorias);
for (int i=0; i<qtdCategorias; i++){
ItemListView item = new ItemListView(categorias[i]);
itens.add(item);
}
adapterListView = new AdapterListView(this, itens);
listview.setAdapter(adapterListView);
listview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
c = json.optJSONArray(position);
String name = null;
String idt = null;
try {
name = c.getString(1);
idt = c.getString(0);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Intent in = new Intent(getApplicationContext(), ProdutosActivity.class);
in.putExtra(TAG_NAME, name);
in.putExtra(TAG_ID, idt);
startActivity(in);
}
});
}
[EDIT]
To request data from server, I use this JSONParser class ():
public class JSONParser{
static InputStream is = null;
static JSONArray jArr = null;
static JSONStringer jArrString = null;
static String json = "";
private static Context context;
private ProgressDialog loader;
// static HttpEntity httpEntity = null;
// constructor
public JSONParser() {
}
public JSONArray getJSONFromUrl(String url, List<NameValuePair> params) {
// Making HTTP request
try {
// defaultHttpClient
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new UrlEncodedFormEntity(params));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
// json = EntityUtils.toString(httpEntity);
// HttpEntity httpEntity2 = httpEntity;
json = EntityUtils.toString(httpEntity);
// is = httpEntity.getContent();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
Log.e("JSONParser", "IOException "+e.toString());
e.printStackTrace();
}
try {
char[] c = new char[json.length()];
json.getChars(0, json.length(), c, 0);
int i = 0;
while (c[i] == '\u00EF' || c[i] == '\u00BB' || c[i] == '\u00BF') { // remove
// utf-8
// BOM
i++;
}
json = json.substring(i);
Log.e("JSON", json);
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
// try parse the string to a JSON object
try {
JSONObject json_data = new JSONObject(json);
JSONArray hashMap_names = json_data.names();
JSONArray hashMap_names2 = new JSONArray();
Map hashMap = new HashMap(json_data.length());
for (int i = 0; i != hashMap_names.length(); i++) {
hashMap.put(String.valueOf(i), json_data.get(String.valueOf(i)));
hashMap_names2.put(String.valueOf(i));
}
JSONObject hashMap_obj = new JSONObject(hashMap);
jArr = hashMap_obj.toJSONArray(hashMap_names2);
// jArr = new JSONArray(json);
Log.e("JSON Parser", "succesful parsing data " + jArr.toString());
} catch (Exception e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
jArr = null;
}
// return JSON String
return jArr;
}
And here I receive the JSON in my class
protected void onActivityResult(int requestCode, int resultCode, Intent data){
if (requestCode == 1){
if (resultCode == RESULT_OK){
try {
json = new JSONArray(data.getStringExtra(TAG_JSON));
Log.e("CategoriasShoppingActivity", "JSON: "+json);
} catch (JSONException e) {
e.printStackTrace();
}
proccess();
}else{ // resultCode == RESULT_CANCELED
Log.d("CategoriasJogarActivity", "AsyncTaskActicity retornou RESULT_CANCELED");
finish();
}
}
}

If you have access to server-side code, it will be easier to sort the list there. If not, your only way to do so, is to parse it to ArrayList and simply sort it using any known algorithm.

Why don't you sort it before serializing ? Use Comparator interface and sort it using Collections.sort. Pass the comparator as as the parameter when sorting

Related

android.os.networkonmainthreadexception error in my request response class for JSON

How should I use my aux class for JSON request, bcoz in android 2,3 work but android 4.x dont work
I read that I need to use Asyntask for fix it, or create thread, I prefer Asyntask but I cant compile it.
How fix my code for asyntask ?
public class Httppostaux {
InputStream is = null;
String result = "";
public JSONArray getserverdata(ArrayList<NameValuePair> parameters, String urlwebserver ){
//conecta via http y envia un post.
httppostconnect(parameters,urlwebserver);
if (is!=null){//si obtuvo una respuesta
getpostresponse();
return getjsonarray();
}else{
return null;
}
}
//peticion HTTP
private void httppostconnect(ArrayList<NameValuePair> parametros, String urlwebserver){
//
try{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(urlwebserver);
httppost.setEntity(new UrlEncodedFormEntity(parametros));
//ejecuto peticion enviando datos por POST
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
}catch(Exception e){
Log.e("log_tag", "Error en la conexión HTTP "+e.toString());
}
}
public void getpostresponse(){
//Convierte respuesta a String
try{
BufferedReader reader = new BufferedReader(new InputStreamReader(is,"iso-8859-1"),8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
result=sb.toString();
Log.e("getpostresponse"," result= "+sb.toString());
}catch(Exception e){
Log.e("log_tag", "Error conviertiendo el resultado "+e.toString());
}
}
public JSONArray getjsonarray(){
//parse json data
try{
JSONArray jArray = new JSONArray(result);
return jArray;
}
catch(JSONException e){
Log.e("log_tag", "Error parsing data "+e.toString());
return null;
}}}
You should not perform network operations on main thread 4.0 and above. Read this to know how to perform network operations correctly https://developer.android.com/training/basics/network-ops/connecting.html
Here i put the sample code for how i use Asyc task for api calling, hope it will help for you and modify this code as per your need,
new Read().execute(); // Asyc Task initialization
public class Read extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
try {
json = lastTweet(); // url executed here and the final value is stored in json obj
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
// Here you call the json obj and do your UI binding.
}
}
public JSONObject lastTweet() throws ClientProtocolException, IOException,
JSONException {
HttpClient client = new DefaultHttpClient();
StringBuilder url = new StringBuilder(<your_URL>);
HttpGet get = new HttpGet(url.toString());
HttpResponse r = client.execute(get);
int status = r.getStatusLine().getStatusCode();
if (status == 200) {
HttpEntity e = r.getEntity();
String data = EntityUtils.toString(e);
Log.e("RESPONSE VALUE IS", data); // Here you get the response
JSONObject last = new JSONObject(data);
return last; //here the response value is returned
} else {
Toast.makeText(getBaseContext(), "error", Toast.LENGTH_SHORT);
return null;
}
}
In your manifest.xml don't forget to add this permission <uses-permission android:name="android.permission.INTERNET" />

JSONException: Value <!DOCTYPE of type java.lang cannot be converted to JSONObject

Guys can you help me a little bit, Im getting this error:
"JSONException: Value <!DOCTYPE of type java.lang cannot be converted to JSONObject"
When I'm parsing the data here is my code:
public class JSONParser {
static InputStream is = null;
static JSONObject jObj = null;
static String json = "";
public JSONParser() {
}
public JSONObject getJSONFromUrl(String url) {
// Making HTTP request
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
json = sb.toString();
}catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
try {
jObj = new JSONObject(json);
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
// return JSON String
return jObj;
}
}
Here is the code where I'm instantiating the Parser:
private void fillSpinnerCabTypes() {
List<String> cabTypesSpinner = new ArrayList<String>();
JSONParser jsonParser = new JSONParser();
JSONObject cabTypesObject = jsonParser.getJSONFromUrl(urlTypeCabs);
try{
TypesArray = cabTypesObject.getJSONArray(TAG_TYPES);
for(int i = 0; i < TypesArray.length(); i++){
JSONObject c = TypesArray.getJSONObject(i);
String name = c.getString(TAG_NAME);
cabTypesSpinner.add(name);
}
}catch(Exception e ){
e.printStackTrace();
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, cabTypesSpinner);
final Spinner spnCabTypes = (Spinner)findViewById(R.id.spnTypeOfCab);
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_item);
spnCabTypes.setAdapter(adapter);
}
I'm really stuck with this. I'm populating the spinner from a database in a backend on Django in the server.
This is my JSON data
{"Types": [{"name": "Normal"}, {"name": "Discapacitados"}, {"name": "Buseta"}]}
This issue comes from the server.
The URL you're requesting, send you back data but not in the JSON format.
The Exception you get is telling you that the String the server send you back starts with:
<!DOCTYPE
This can be:
A simple webpage (instead of raw JSON). It correspond to the first XML tag of a web page (source)
An error page generated by the server, and printed in HTML
To debug this further, simply print the content of your json variable in the logcat:
Log.d("Debug", json.toString());
jObj = new JSONObject(json);
This problem came in my code also.and solution was different.It occured due to spelling mistake of webservice.
Solution 1:
for example real the url is
http://example.com/directory/file.php
and i had used
http://example.com/directory/file1.php
Solution 2:
use loopj library .it exactly gives you the explained error.
AsyncHttpClient client = new AsyncHttpClient();
client.post(str , localRequestParams, new AsyncHttpResponseHandler() {
#Override
public void onFinish() {
super.onFinish();
Log.i("onFinish","onFinish");
}
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
Log.i("onSuccess","onSuccess");
}
#Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
Log.i("onFailure","onFailure");
}
});

Grabbing JSON content with Java

Here is a sample of my json_encode in PHP:
print(json_encode($row));
leads to {"AverageRating":"4.3"} which is good.
But in Java, I can not seem to grab this 4.3 value. Here it is (for an Android project) I have edited non-relevant data.
public class Rate extends ListActivity {
JSONArray jArray;
String result = null;
InputStream is = null;
StringBuilder sb = null;
String Item, Ratings, Review, starAvg;
RatingBar ratingsBar;
ArrayList<NameValuePair> param;
public void onCreate(Bundle savedInstanceState) {
starAvg = "0"; // Sets to 0 in case there are no ratings yet.
new starRatingTask().execute();
ratingsBar = (RatingBar) findViewById(R.id.theRatingBar);
class starRatingTask extends AsyncTask<String, String, Void> {
InputStream is = null;
String result = "";
#Override
protected Void doInBackground(String... params) {
String url_select = "http://www.---.com/---/average_stars.php";
ArrayList<NameValuePair> param = new ArrayList<NameValuePair>();
param.add(new BasicNameValuePair("item", Item));
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url_select);
try {
httpPost.setEntity(new UrlEncodedFormEntity(param));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
// read content
is = httpEntity.getContent();
} catch (Exception e) {
Log.e("log_tag", "Error in http connection " + e.toString());
}
try {
BufferedReader br = new BufferedReader(
new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
result = sb.toString();
} catch (Exception e) {
Log.e("log_tag", "Error converting result " + e.toString());
}
return null;
}
protected void onPostExecute(Void v) {
String starAvgTwo = null;
try {
jArray = new JSONArray(result);
JSONObject json_data = null;
for (int i = 0; i < jArray.length(); i++) {
json_data = jArray.getJSONObject(i);
starAvg = json_data.getString("AverageRating");
starAvgTwo = starAvg;
}
} catch (JSONException e1) {
Toast.makeText(getBaseContext(), "No Star Ratings!",
Toast.LENGTH_LONG).show();
} catch (ParseException e1) {
e1.printStackTrace();
}
Toast.makeText(getBaseContext(), starAvgTwo,
Toast.LENGTH_LONG).show();
ratingsBar.setRating(Float.valueOf(starAvg));
}
}
That second toast produces a blank (I assume a "" - empty string?). If I change the toast variable back to starAvg, then it toasts "0".
How can I retrieve the value of 4.3.
As we discussed in the comments on the original question, the PHP is sending down as single JSONObject rather than an array. Parsing as a JSONObject is required in it's present state; however, if you begin sending down an array of your value objects, then you'd use JSONArray to parse it.
I think your JSON doesn't contain array. so just do this:
JSONObject jsonObject = new JSONObject(result); //to convert string to be a JSON object
String averageRating = jsonObject.getString("AverageRating"); //get the value of AverageRating variable
and try toast the averageRating.
and how to get the array from JSON object?
if you have JSON:
{"employees": [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName":"Jones" }]
}
then use this code
JSONArray jsonArray = new JSONArray(result);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
Log.i(Rate.class.getName(), jsonObject.getString("firstName"));
}
that code will produce
John Anna Peter
in your LogCat

Json Parsin in android

http://www.taxmann.com/TaxmannWhatsnewService/Services.aspx?service=getStatutesTabNews
This is my web service. I want to parse it and I want show news_id and news title. Please post, showing me how to parse it so that I can store all the values in a string. I tried but am getting Exception ..
try
{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.taxmann.com/TaxmannWhatsnewService/Services.aspx?service=getStatutesTabNews");
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
}catch(Exception e)
{
Log.e("log_tag", "Error in http connection"+e.toString());
}
//convert response to string
try
{
BufferedReader reader = new BufferedReader(new InputStreamReader(is,"UTF-8"),8);
sb = new StringBuilder();
sb.append(reader.readLine() + "\n");
String line="0";
while ((line = reader.readLine()) != null)
{
sb.append(line + "\n");
}
is.close();
result=sb.toString();
}catch(Exception e)
{
Log.e("log_tag", "Error converting result "+e.toString());
}
// String name;
try
{
jArray = new JSONArray(result);
JSONObject json_data=null;
for(int i=0;i<jArray.length();i++)
{
HashMap<String, String> map = new HashMap<String, String>();
json_data = jArray.getJSONObject(i);
// name=json_data.getString("name");
map.put("id", String.valueOf(json_data.getString("news_id")));
map.put("title",json_data.getString("news_title"));
map.put("shortdescription",json_data.getString("news_short_description"));
map.put("date",json_data.getString("news_date"));
mylist.add(map);
}
}
catch(Exception e)
{
}
}
You can parse using Gson parser.
So first download gson-1.1.jar file from http://findjar.com/jar/com/google/code/gson/gson/1.1/gson-1.1.jar.html
and then add jar file into your project build path then use the below code for parsing (Simple replace your parsing code with below code)
try
{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.taxmann.com/TaxmannWhatsnewService/Services.aspx?service=getStatutesTabNews");
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
String data = EntityUtils.toString(entity);
Gson gson = new Gson();
Type collectionType = new TypeToken<List<NewsData>>(){}.getType();
List<NewsData> details = gson.fromJson(data, collectionType);
}
catch (Exception e)
{
Log.i("error","error");
e.printStackTrace();
}
bean for above code is
public class NewsData
{
private String news_id = null;
private String news_title = null;
private String news_short_description = null;
private String news_date = null;
public String getNews_id()
{
return news_id;
}
public void setNews_id(String newsId)
{
news_id = newsId;
}
public String getNews_title()
{
return news_title;
}
public void setNews_title(String newsTitle)
{
news_title = newsTitle;
}
public String getNews_short_description()
{
return news_short_description;
}
public void setNews_short_description(String newsShortDescription)
{
news_short_description = newsShortDescription;
}
public String getNews_date()
{
return news_date;
}
public void setNews_date(String newsDate)
{
news_date = newsDate;
}
}
and add internet permission in your manifest
<uses-permission
android:name="android.permission.INTERNET" />
I hope this will help you.
if you still not get your result you can use below code .
static InputStream is = null;
static JSONObject jObj = null;
static JSONArray jsonArray=null;
static String json = "";
mJsonArray=getJSONFromUrl(url);
try{
JSONObject mJsonObject=null;
for(int i =0;i<mJsonArray.length();i++){
if(!mJsonArray.isNull(i)){
HashMap<String, String> map = new HashMap<String, String>();
mJsonObject=mJsonArray.getJSONObject(i);
map.put("title",mJsonObject.getString("news_title"));
map.put("shortdescription",mJsonObject.getString("news_short_description"));
map.put("date",mJsonObject.getString("news_date"));
//add you map in to list
}
}
}catch(JSONException jexc){
jexc.printStackTrace();
}
public JSONArray getJSONFromUrl(String url) {
// Making HTTP request
try {
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
json = sb.toString();
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
// try parse the string to a JSON object
try {
jsonArray =new JSONArray(json);
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
// return JSON String
return jsonArray;
}

Looping and converting JSON Object to Array

I'm new to Java and programming for Android and I've seen a lot of tutorials but I am kinda clueless atm on how to loop through a JSONObject and set it to my class.
Example of JSON data:
http://sickbeard.com/api/#history
Class I made:
public Episode(JSONObject obj) {
try {
this.id = Integer.parseInt(obj.getString("episode").toString());
this.tvId = Integer.parseInt(obj.getString("tvdbid").toString());
this.resource = obj.getString("resource").toString();
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
I came as far as this...
ArrayList<Episode> episodeList = new ArrayList<Episode>();
JSONObject data = new JSONObject();
for(int i = 0; i < 2; i++) {
try {
data = response.getJSONObject("data");
episodeList.add(new Episode(data));
} catch (JSONException e) {
e.printStackTrace();
}
}
return null;
// for each entry create new episode :)
} else {
return null;
}
Found it :)
try {
response = new JSONObject(con.query("history", parameters));
JSONArray data = response.getJSONArray("data");
for(int i = 0; i < data.length(); i++) {
try {
episodeList.add(new Episode((JSONObject) data.get(i)));
} catch (JSONException e) {
e.printStackTrace();
}
}
} catch (JSONException e) {
e.printStackTrace();
}
// is = entity.getContent();
ArrayList<String> myList = new ArrayList<String>();
//convert response to string
try{
BufferedReader reader = new BufferedReader(new InputStreamReader(is,"iso-8859-1"),8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
result = sb.toString();
} catch (Exception e) {
Log.e("log_tag", "Error converting result "+e.toString());
}
//parse json data
try{
jArray = new JSONArray(result);
for(int i=0;i<jArray.length();i++){
json_data = jArray.getJSONObject(i);
myList.add(json_data.getString("id"));
Log.i("log_tag","id: " + json_data.getString("id"));
}
}
catch(JSONException e){
Log.e("log_tag", "Error parsing data "+e.toString());
}
return myList;
// then u can recieve this myList :
ArrayList<String> get_data_id = postData();
// get_data_id = myList
get_data_id.get(0) - it is first element,
get_data_id.get(1) - it is second element
....
EXAMPLE
json data is : [{"id":"1"},{"id":"2"},{"id":"3"},{"id":"4"},{"id":"5"},{"id":"6"}]
{in loop} myList.add(json_data.getString("id"));
get_data_id.get(0) = 1
get_data_id.get(1) = 2
get_data_id.get(2) = 3
..........
:)
Good Luck

Categories