Not Getting Response of USSD Code in Android - java

I want to dial and get the dialed USSD code response. Here is my code. but when I run it doesn't show any response on the toast.
private void ussdResponse(String completeCode) {
TelephonyManager manager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
if (checkSelfPermission(Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED || checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, requestCode);
ActivityCompat.requestPermissions(MainActivity.this , new String[]{Manifest.permission.READ_PHONE_STATE},requestCode);
return;
}
manager.sendUssdRequest(completeCode, new TelephonyManager.UssdResponseCallback() {
#Override
public void onReceiveUssdResponse(TelephonyManager telephonyManager, String request, CharSequence response) {
super.onReceiveUssdResponse(telephonyManager, request, response);
Toast.makeText(MainActivity.this, "Success", Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, "USSD Result"+response.toString(), Toast.LENGTH_LONG).show();
}
#Override
public void onReceiveUssdResponseFailed(TelephonyManager telephonyManager, String request, int failureCode) {
super.onReceiveUssdResponseFailed(telephonyManager, request, failureCode);
Toast.makeText(MainActivity.this, "Failed", Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, "USSD Response Failed.", Toast.LENGTH_SHORT).show();
}
}, new Handler());
}
compleCode contains the USSD Code. But the Toast shows Nothing.
can any one please find me the solution.? Or is there any other way to get the dialed USSD response in my app?

I found the answer myself. I Used this Api to resolve the problem.
https://github.com/romellfudi/VoIpUSSD
Here is my code:
HashMap map = new HashMap<>();
map.put("KEY_LOGIN",new HashSet<>(Arrays.asList("espere", "waiting", "loading", "esperando")));
map.put("KEY_ERROR",new HashSet<>(Arrays.asList("problema", "problem", "error", "null")));
final USSDApi ussdApi = USSDController.getInstance(MainActivity.this);
ussdApi.callUSSDInvoke("*786#", map, new USSDController.CallbackInvoke() {
#Override
public void responseInvoke(String message) {
// message has the response string data
String dataToSend = "data";// <- send "data" into USSD's input text
ussdApi.send(dataToSend,new USSDController.CallbackMessage(){
#Override
public void responseMessage(String message) {
// message has the response string data from USSD
Log.d("message", message);
}
});
}
#Override
public void over(String message) {
// message has the response string data from USSD or error
// response no have input text, NOT SEND ANY DATA
}
});

Related

Login to Firebase using phone returns null pointer

I'm trying to follow the tutorial from Firebase to allow users to login using their phone number. I've watched a tutorial video. All my code looks correct, but when I try it on my test device I receive a null pointer error.
at com.google.android.gms.common.internal.Preconditions.checkNotNull(Unknown Source)
at com.google.firebase.auth.PhoneAuthProvider.verifyPhoneNumber(Unknown Source)
at studios.p9p.chatomatic.chat_o_matic.PhoneLogin.CheckPhoneNumber(PhoneLogin.java:92)
at studios.p9p.chatomatic.chat_o_matic.PhoneLogin.access$000(PhoneLogin.java:29)
at studios.p9p.chatomatic.chat_o_matic.PhoneLogin$1.onClick(PhoneLogin.java:52)
My code for the phone login is as follows:
private EditText et_check_phone_number;
private EditText et_verify_code;
private Button btn_phone;
private Button btn_verify;
private String getPhoneNumber, getVerifactionCode;
private String mVerificationId = "";
private FirebaseAuth mAuth;
private FirebaseDatabase db;
private PhoneAuthProvider.OnVerificationStateChangedCallbacks mcallBacks;
private PhoneAuthProvider.ForceResendingToken mResendToken;
private ProgressDialog mloading;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_phone_login);
mAuth = FirebaseAuth.getInstance();
initVariables();
btn_phone.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
CheckPhoneNumber();
}
});
btn_verify.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
VerifyPhoneNumber();
}
});
}
private void initVariables() {
et_check_phone_number = findViewById(R.id.et_phonenumber);
et_verify_code = findViewById(R.id.etvarifaction);
btn_phone = findViewById(R.id.btn_phone_login);
btn_verify = findViewById(R.id.btn_phone_verify);
mloading = new ProgressDialog(this);
}
private void CheckPhoneNumber() {
getPhoneNumber = et_check_phone_number.getText().toString();
if (TextUtils.isEmpty(getPhoneNumber))
{
Toast.makeText(this, "Phone Number Field Cant Be Empty...", Toast.LENGTH_SHORT).show();
} else{
mloading.setTitle("Checking Your Phone Number");
mloading.setMessage("It Gonna Take A Second...");
mloading.setCanceledOnTouchOutside(false);
mloading.setIcon(R.mipmap.ic_launcher);
mloading.show();
PhoneAuthProvider.getInstance().verifyPhoneNumber(
getPhoneNumber, // Phone number to verify
60, // Timeout duration
TimeUnit.SECONDS, // Unit of timeout
this, // Activity (for callback binding)
mcallBacks);
}
}
mcallBacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
signInWithPhoneAuthCredential(phoneAuthCredential);
}
#Override
public void onVerificationFailed(FirebaseException e) {
Toast.makeText(PhoneLogin.this, "Wrong Or Invalid Phone Number...", Toast.LENGTH_SHORT).show();
btn_phone.setVisibility(View.VISIBLE);
et_check_phone_number.setVisibility(View.VISIBLE);
et_verify_code.setVisibility(View.INVISIBLE);
btn_verify.setVisibility(View.INVISIBLE);
if (e instanceof FirebaseAuthInvalidCredentialsException) {
Toast.makeText(getBaseContext(), "Invalid Request " + e.toString(), Toast.LENGTH_SHORT).show();
} else if (e instanceof FirebaseTooManyRequestsException) {
Toast.makeText(getBaseContext(), "The SMS quota for the project has been exceeded " + e.toString(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCodeSent(String verificationId,
PhoneAuthProvider.ForceResendingToken token) {
// Save verification ID and resending token so we can use them later
mVerificationId = verificationId;
mResendToken = token;
Toast.makeText(PhoneLogin.this, "Code Sent Please Check Your SMS...", Toast.LENGTH_SHORT).show();
btn_phone.setVisibility(View.INVISIBLE);
et_check_phone_number.setVisibility(View.INVISIBLE);
et_verify_code.setVisibility(View.VISIBLE);
btn_verify.setVisibility(View.VISIBLE);
}
};
}
private void VerifyPhoneNumber() {
getVerifactionCode = et_verify_code.getText().toString();
if (TextUtils.isEmpty(getVerifactionCode)){
Toast.makeText(this, "Please Enter The Code Sent To Your SMS...", Toast.LENGTH_SHORT).show();
}else{
mloading.setTitle("Checking Your Verification code ");
mloading.setMessage("Ill Be Back In A Jiffy...");
mloading.setCanceledOnTouchOutside(false);
mloading.setIcon(R.mipmap.ic_launcher);
mloading.show();
PhoneAuthCredential credential = PhoneAuthProvider.getCredential(mVerificationId, getVerifactionCode);
signInWithPhoneAuthCredential(credential);
}
}
private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
mloading.dismiss();
Toast.makeText(PhoneLogin.this, "Login Successful...", Toast.LENGTH_SHORT).show();
Intent phoneloginIntent =new Intent (getBaseContext(),Home_Screen.class);
phoneloginIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(phoneloginIntent);
finish();
} else {
String mesage = task.getException().toString();
Toast.makeText(PhoneLogin.this, "Error: " + mesage, Toast.LENGTH_SHORT).show();
}
}
});
}
The "+44" I added trying to see if I was entering the wrong phone number. I tried it by adding the +44 manually into the edit text of the app first and that gave the same error.
Edit
So I've removed the line inside the Auth provider that asked if the number was larger than 9 digits as it wasn't working. Also I ran a log to see if it capturing the phone number correctly.
Log.i("Verify_Phone_Number",getPhoneNumber);
2019-07-16 14:15:30.585 32055-32055/studios.p9p.chatomatic.chat_o_matic I/Verify_Phone_Number: +447******100 and it returns correctly
Edit 2
So on further testing if I click btn_phone before entering the phone number it works correctly, but if I simply add the phone number to the edit test first then press thebtn_phone it crashes with the above message in logcat.
As per Firebase Docs you have to pass the Number with Country Code :
E.g.
phone number = +919090909090
See Following Picture :
As you can see even testing number needs country code with them.
When your app crashes it means Firebase PhoneAuthProvider.getInstance().verifyPhoneNumber() not getting the number with country code.
You can try this following code before passing to if condition :
if (et_check_phone_number.getText().toString().startsWith("+44"){
getPhoneNumber = et_check_phone_number.getText().toString();
}else{
getPhoneNumber = "+44"+et_check_phone_number.getText().toString();
}
Above Code will check whether user put prefix of your country code or not.
Ok so the way i solved this problem was to move the mcallbacks to the on create section of code. as shown below
setContentView(R.layout.activity_phone__login);
mAuth = FirebaseAuth.getInstance();
InitVariables();
AddPhoneNumberButtons();
mcallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
#Override
public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
signInWithPhoneAuthCredential(phoneAuthCredential);
}
#Override
public void onVerificationFailed(FirebaseException e) {
Toast.makeText(getBaseContext(), "Wrong Or Invalid Phone Number...", Toast.LENGTH_SHORT).show();
AddPhoneNumberButtons();
if (e instanceof FirebaseAuthInvalidCredentialsException) {
Toast.makeText(getBaseContext(), "Invalid Request " + e.toString(), Toast.LENGTH_SHORT).show();
} else if (e instanceof FirebaseTooManyRequestsException) {
Toast.makeText(getBaseContext(), "The SMS quota for the project has been exceeded " + e.toString(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCodeSent(String verificationId,
PhoneAuthProvider.ForceResendingToken token) {
// Save verification ID and resending token so we can use them later
verificationid = verificationId;
mresendtoken = token;
Toast.makeText(getBaseContext(), "Code Sent Please Check Your SMS...", Toast.LENGTH_SHORT).show();
AddVerifyButtons();
}
};

Not Getting Resposne when making Request using volley

I'm trying to make a request to server using volley and check the returned value contains specific value or not. It works when I use separate class and call from Mainactivity using intent in onCreate.
But I would like to make a call manually when button is clicked from fragment but when button is clicked nothing happens.
Here is my code:
mCeload = (FloatingActionButton) view.findViewById(R.id.Update);
mCeload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String url = "https://cmprc.edu.np/batch/update.json";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new com.android.volley.Response.Listener<String>() {
#Override
public void onResponse(String response) {
if(response != null ) {
boolean resp = response.contains("1");
if (!resp) {
Toast.makeText(getActivity(), "Contacts are Updated", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getActivity(), "No Updates Availaible", Toast.LENGTH_SHORT).show();
}
}
}
}, new com.android.volley.Response.ErrorListener(){
#Override
public void onErrorResponse(VolleyError volleyError) {
volleyError.printStackTrace();
}
});
Toast.makeText(getActivity(), "You clicked the Button", Toast.LENGTH_SHORT).show();
}
});
I"m positive that button is clicked since I"m getting last toast message but before that nothing happens and I"m not getting any Toast of whether response was positive or negative.
Also How do i get the response as string and store in local database such that I could compare the saved value with new one when user check for updates and if both value matches then show Toast of no updates available and if not then show updates available.
Thanks in advance.
Add your request on the RequestQueue like this way:
final RequestQueue requestQueue = Volley.newRequestQueue(getActivity);
String url = "https://cmprc.edu.np/batch/update.json";
// Initialize a new StringRequest
StringRequest stringRequest = new StringRequest(
Request.Method.GET,
url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
if(response != null ) {
boolean resp = response.contains("1");
if (!resp) {
Toast.makeText(getActivity(), "Contacts are Updated", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getActivity(), "No Updates
Availaible", Toast.LENGTH_SHORT).show();
} }
},
new Response.ErrorListener() {
#Override
public void
onErrorResponse(VolleyError error) {
volleyError.printStackTrace();
}
}
);
// Add StringRequest to the RequestQueue
requestQueue.add(stringRequest);

How to call a toast message on success callback in class

I'm working on a POST API using okhttp library. Everything is working fine except I'm unable to find a way to show a simple toast message on it's success callback. How can I call a toast message to the user so he knows wether data is posted on server or not in the success and failure callbacks?
P.S the code below is in a different class not in a activity class.
This is my code:
public DataSource(Context context) {
this.mContext = context;
mDbHelper = new DBHelper(mContext);
mDatabase = mDbHelper.getWritableDatabase();
}
post(URL, jsonData, new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.i("FAILED", "onFailure: Failed to upload data to server");
//here I want to show toast message
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
Log.i("SUCCESSFUL", "onSuccess: data uploaded");
//here I want to show toast message
} else {
Log.i("UN SUCCESSFUL", "onFailure: Failed to upload data to server");
//here I want to show toast message
}
}
});
Every app has its own special thread that runs UI objects such as View objects; this thread is called the UI thread. Only objects running on the UI thread have access to other objects on that thread. Because tasks that you run on a thread from a thread pool aren't running on your UI thread, they don't have access to UI objects. To move data from a background thread to the UI thread, use a Handler that's running on the UI thread or can use android implementation for the same as shown here.
- Case 1
MyActivity.this.runOnUiThread(new Runnable() {
#Override
void run() {
Toast.makeText(MyActivity.this,
"message", Toast.LENGTH_LONG).show();
});
- Case 2
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast.makeText(MyActivity.this,
"message", Toast.LENGTH_LONG).show();
}
});
Had it been Main thread you would have used it directly like
Toast.makeText(MyActivity.this,
"message", Toast.LENGTH_LONG).show();
This callback is an asynchronous function, and you can change View just in UI-thread, so Handler will be helpd for you.
....
private final static int MSG_SUCCESS = 0x0001;
private final static int MSG_FAIL = 0x0002;
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch(msg.what){
case MSG_SUCCESS:
//Toast success
break;
case MSG_FAIL:
//Toast fail
break;
default:
break;
}
}
};
......
......
if (response.isSuccessful()) {
Log.i("SUCCESSFUL", "onSuccess: data uploaded");
handler.sendEmptyMessage(MSG_SUCCESS);
} else {
Log.i("UN SUCCESSFUL", "onFailure: Failed to upload data to server");
handler.sendEmptyMessage(MSG_FAIL);
}
......
You are getting error
java.lang.RuntimeException: Can't create handler inside thread that
has not called Looper.prepare()
Because you're calling it from a worker thread. You need to call Toast.makeText() (and most other functions dealing with the UI) from within the main thread. You could use a handler,
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
Log.i("SUCCESSFUL", "onSuccess: data uploaded");
context.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(context, "SUCCESSFUL", Toast.LENGTH_SHORT).show();
}
});
}
Just send the context of your activity while calling this method:
void methodName(Context c){
post(URL, jsonData, new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.i("FAILED", "onFailure: Failed to upload data to server");
//here I want to show toast message
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
Log.i("SUCCESSFUL", "onSuccess: data uploaded");
Toast.makeText(c,"message",Toast.LENGTH_SHORT).show();
//here I want to show toast message
} else {
Log.i("UN SUCCESSFUL", "onFailure: Failed to upload data to server");
//here I want to show toast message
}
}
});
}
Try this
TaskActivity.this.runOnUiThread(new Runnable() {
#Override
void run() {
Toast msg = Toast.makeText(TaskActivity.this,
"message", Toast.LENGTH_LONG);
msg.show();
});
Try this
Toast.makeText(YourActivity.this, "Your Message", Toast.LENGTH_SHORT).show();
Activity
post(URL, jsonData, new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.i("FAILED", "onFailure: Failed to upload data to server");
//here I want to show toast message
Toast.makeText(YourActivity.this, "Your Message", Toast.LENGTH_SHORT).show();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
Log.i("SUCCESSFUL", "onSuccess: data uploaded");
//here I want to show toast message
Toast.makeText(YourActivity.this, "Your Message", Toast.LENGTH_SHORT).show();
} else {
Log.i("UN SUCCESSFUL", "onFailure: Failed to upload data to server");
//here I want to show toast message
Toast.makeText(YourActivity.this, "Your Message", Toast.LENGTH_SHORT).show();
}
}
});
Fragment
post(URL, jsonData, new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.i("FAILED", "onFailure: Failed to upload data to server");
//here I want to show toast message
Toast.makeText(getActivity(), "Your Message", Toast.LENGTH_SHORT).show();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
Log.i("SUCCESSFUL", "onSuccess: data uploaded");
//here I want to show toast message
Toast.makeText(getActivity(), "Your Message", Toast.LENGTH_SHORT).show();
} else {
Log.i("UN SUCCESSFUL", "onFailure: Failed to upload data to server");
//here I want to show toast message
Toast.makeText(getActivity(), "Your Message", Toast.LENGTH_SHORT).show();
}
}
});
Edit
Handler handler = new Handler();
handler.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(mContext, "Your Message", Toast.LENGTH_SHORT).show();
}
});

Facebook API doesn't return email

I know that this question has been asked, but there is only one answer pretty much or is not even answered.
I dont know if it's my lack of understanding or lack of Facebook documentation, but so far i have this code to retrieve user email.
callbackManager = CallbackManager.Factory.create();
mFbLoginManager.registerCallback(
callbackManager,
new FacebookCallback < LoginResult > () {
#Override
public void onSuccess(final LoginResult loginResult) {
// Handle success
Log.i(TAG, "callBack Login Result: LoginManager success - " + loginResult.toString());
GraphRequest.newMeRequest(loginResult.getAccessToken(), new GraphRequest.GraphJSONObjectCallback() {
#Override
public void onCompleted(JSONObject userObject, GraphResponse response) {
if (response.getError() == null) {
try {
AccessToken token = AccessToken.getCurrentAccessToken();
Log.e(TAG, token.getToken());
Log.e(TAG, userObject.toString());
email = userObject.getString("email");
} catch (JSONException ex) {
Log.e(TAG, "Not such permissions for email!");
ex.printStackTrace();
}
Log.d(TAG, "Email fetched: " + email);
}else{
Log.e(TAG, "Something went wrong with fetching email with GraphRequest");
}
}
}).executeAsync();
}
The JSON string returns only the name and the id, therefore my email variable is empty.
The part i am troubled with is that when i test it on Graph Explorer or with that link, i get the email.
I have se permissions also on the developers site dashboard and also in my code(that's inside onClick() when user press the facebook login button):
mFbLoginManager.logInWithReadPermissions(LoginActivity.this, Arrays.asList("user_photos", "email", "public_profile")
So i am not sure what is the problem in my code. The login button is custom and not the facebook LoginButton, i dont know if that matters.
Every help is welcome
Add below depandancy in Gradle
implementation 'com.facebook.android:facebook-android-sdk:4.11.0'
enter code here
FacebookSdk.sdkInitialize(this);
callbackManager =CallbackManager.Factory.create();
// -----start putting in oncreate-----------------------
LoginManager.getInstance().logInWithReadPermissions(UserActivity.this, Arrays.asList("public_profile", "user_friends","email"));
facebookTime();
//----onclicklisterner ---------------/
callbackManager.onActivityResult(requestCode,resultCode,data);
//---onactivityresult-------------/
public void facebookTime() {
LoginManager.getInstance().registerCallback(callbackManager,
new FacebookCallback<LoginResult>() {
#Override
public void onSuccess(LoginResult loginResult) {
System.out.println("Success");
GraphRequest request = GraphRequest.newMeRequest(
loginResult.getAccessToken(), new GraphRequest.GraphJSONObjectCallback() {
#Override
public void onCompleted(JSONObject object, GraphResponse response) {
// Util.showCenteredToast(getActivity(), "object" + object);
// Util.showCenteredToast(getActivity(), "GraphResponse" + response);
try {
strEmail = object.getString("email");
strUserName = object.getString("name");
String id = object.getString("id");
// write your code here
//asyncTask.iSocialMediaResponse = LoginFragment.this;
asyncTask.execute();
} catch (JSONException e) {
e.printStackTrace();
}
}
});
Bundle parameters = new Bundle();
parameters.putString("fields", "email,name");
//parameters.putString("fields", "user_friends");
request.setParameters(parameters);
//Log.e(" About to Graph Call", " ");
request.executeAsync();
}
#Override
public void onCancel() {
// App code
Util.showCenteredToast(UserActivity.this, "oncancel");
}
#Override
public void onError(FacebookException exception) {
// App code
Util.showCenteredToast(UserActivity.this, "exception" + exception);
}
});
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
callbackManager.onActivityResult(requestCode, resultCode, data);
}

Facebook invite- Rarely invitation gets delivered after many hours

I have done the task on "Inviting users to the app using facebook" in android, used the below codes as a result if i send the invitation, the invite message rarely delivers after many hours and or else not getting delivered, do anybody know the solution for this?
final ImageView facebook1 = (ImageView) findViewById(R.id.facebook1);
facebook1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v){
Facebook mFacebook = new Facebook( APP_ID );
Bundle params = new Bundle();
params.putString("message", "Prova ");
mFacebook.dialog(Singlemenuitem.this, "apprequests", params, new DialogListener() {
public void onComplete(Bundle values) {
Toast toast = Toast.makeText(getApplicationContext(), "Done",
Toast.LENGTH_SHORT);
toast.show();
}
public void onFacebookError(FacebookError error) {
Toast.makeText(getApplicationContext(), "Facebook Error: " + error.getMessage(),
Toast.LENGTH_SHORT).show();
}
public void onCancel() {
Toast toast = Toast.makeText(getApplicationContext(), "App request cancelled",
Toast.LENGTH_SHORT);
toast.show();
}
public void onError(DialogError e) {
// TODO Auto-generated method stub
}
});
} });

Categories