I have the following method in the presenter.
public void addNote(int customerId, String body) {
disposables = RxUtil.initDisposables(disposables);
if (TextUtils.isEmpty(body)) {
view.showNoteTextEmpty();
return;
}
if (customerId == Constants.ZERO) {
view.showNoteError("There is a problem with adding note. Try again!");
return;
}
Disposable disposable = userPrefRepository.getLoggedInUser()
.subscribeOn(Schedulers.io())
.map(user -> getNote(body, user))
.flatMap(note -> customersRepository.addNote(customerId, note))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> {
if (response.isSuccessful()) {
view.onNoteAdded();
} else if (response.code() == 401) {
view.handleUnauthorisedError();
} else {
view.onNoteNotAdded();
}
}, view::handleError);
disposables.add(disposable);
}
Now I want to unit test it with the following class:
#RunWith(PowerMockRunner.class) #PrepareForTest(TextUtils.class)
public class NoteDetailsPresenterTest extends BaseTest {
#Rule TrampolineSchedulerRule trampolineSchedulerRule = new TrampolineSchedulerRule();
#Mock CustomersRepository customersRepository;
#Mock UserRepository userRepository;
#Mock RolesManager rolesManager;
#Mock NoteDetailsPresenter.View view;
private NoteDetailsPresenter presenter;
#Before
public void setUp() {
mockTextUtils();
presenter = new NoteDetailsPresenter(customersRepository, userRepository, rolesManager);
presenter.setView(view);
}
#Test
public void shouldAddNote() {
// Given
User user = User.newBuilder()
.withUserId(1)
.build();
// When
Mockito.when(userRepository.getLoggedInUser()).thenReturn(Single.just(user));
Note note = presenter.getNote("Note body", user);
Response<Note> response = Response.success(200, note);
Mockito.when(customersRepository.addNote(1, note)).thenReturn(Single.just(response));
presenter.addNote(1, "Note body");
// Then
Mockito.verify(view).onNoteAdded();
}
}
But it fails with the following exception:
Wanted but not invoked:
view.onNoteAdded();
-> at com.anstar.presentation.notes.NoteDetailsPresenterTest.shouldAddNote(NoteDetailsPresenterTest.java:56)
However, there were other interactions with this mock:
view.handleError(
java.lang.NullPointerException: The single returned by the mapper is null
);
-> at io.reactivex.internal.observers.ConsumerSingleObserver.onError(ConsumerSingleObserver.java:46)
How I can solve it? Is is the problem regarding map and flatMap transformations?
It seems that the mock can't be read. Try to put any() on the parameters:
Instead of this:
Mockito.when(customersRepository.addNote(1, note)).thenReturn(Single.just(response));
Use any():
Mockito.when(customersRepository.addNote(anyInt(), any(Note.class))).thenReturn(Single.just(response));
Why the mock can't read?
If parameters are primitive data types (string, int, double, etc) you can just pass the exact parameter (in your case, the first parameter which is integer, 1) and the mock will be read. However in objects (in your case, Note object), even though you have the same exact parameters, they will have different hashCode() so the mock can' t be read. Solution for this is to accept any() parameter specifying the class type: any(Note.class).
Related
I have a bit problem setting up proper unit tests for my interactor classes in my android app. These classes is where I have "business logic" of my app.
Here is one such class:
public class ChangeUserPasswordInteractor {
private final FirebaseAuthRepositoryType firebaseAuthRepositoryType;
public ChangeUserPasswordInteractor(FirebaseAuthRepositoryType firebaseAuthRepositoryType) {
this.firebaseAuthRepositoryType = firebaseAuthRepositoryType;
}
public Completable changeUserPassword(String newPassword){
return firebaseAuthRepositoryType.getCurrentUser()
.flatMapCompletable(firebaseUser -> {
firebaseAuthRepositoryType.changeUserPassword(firebaseUser, newPassword);
return Completable.complete();
})
.observeOn(AndroidSchedulers.mainThread());
}
}
Here is a test I wrote:
#RunWith(JUnit4.class)
public class ChangeUserPasswordInteractorTest {
#Mock
FirebaseAuthRepositoryType firebaseAuthRepositoryType;
#Mock
FirebaseUser firebaseUser;
#InjectMocks
ChangeUserPasswordInteractor changeUserPasswordInteractor;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
RxAndroidPlugins.reset();
RxAndroidPlugins.setInitMainThreadSchedulerHandler(schedulerCallable -> Schedulers.trampoline());
}
#Test
public void changeUserPassword() {
Mockito.when(firebaseAuthRepositoryType.getCurrentUser()).thenReturn(Observable.just(firebaseUser));
Mockito.when(firebaseAuthRepositoryType.changeUserPassword(firebaseUser, "test123")).thenReturn(Completable.complete());
changeUserPasswordInteractor.changeUserPassword("test123")
.test()
.assertSubscribed()
.assertNoErrors()
.assertComplete();
}
}
Problem here I am having is that this test completes with no errors, even If I change the password from "test123" on changeUserPassword invokation to something else, or if I in the mock return "Completable.onError(new Throwable())".
I can't understand this behavior. Any suggestions how to set up the test?
The last line of your flatMapCompletable always returns Completable.complete()
it should be :
firebaseAuthRepositoryType.changeUserPassword(firebaseUser, newPassword);
so :
public Completable changeUserPassword(String newPassword){
return firebaseAuthRepositoryType.getCurrentUser()
.flatMapCompletable(firebaseUser ->
firebaseAuthRepositoryType.changeUserPassword(firebaseUser, newPassword));
}
In my current Android project I am investigating the use of Kotlin.
I am rewriting a 100% Java Android app to 100% Kotlin.
I'm stuck with attempting to implement my Java step builders though.
I employed Java step Builders as they force users of my code to supply all required data and/or functions before being able to execute an associated RxJava process.
These RxJava processes are complex and I wished to simplify their initialisation and execution as much as possible.
The use of Java Step builders allow developers to write the following code:-
Sequence.builder()
.stepOne(one)
.stepTwo(two)
.stepThree(three)
.build()
.execute();
What I am looking for is a Kotlin version of this approach.
My initial thought was that Kotlin would support Builders and Step Builders.
I am not "precious" about employing Builders in Kotlin, the Kotlin solution must force the developers that use my code to have supplied all required data and/or functions before they are able to execute the associated "executed" code.
From investigating Kotlin I've discovered internal DSLs which are sounding both interesting topic in themselves and a possible solution to this particular question.
I have a number of Step Builders to implement, none of these have more than 6 parameters. I do like to try and keep to SOLID no more than three parameters rule though.
Also if it makes any difference, some of the passed parameters are RxJava Actions and Consumers. Default values are not relevant here as none of the parameters have viable default values.
UPDATE
My Java step builders all resemble this:-
public class ExampleSequence extends Sequence {
private static final String TAG = "ExampleSequence";
private final Action onComplete;
private final Consumer<? super Throwable> onError;
/**
* #param builder
*/
private ExampleSequence(final Builder builder) {
super(builder.getDoLoginRefreshFail());
this.onError = builder.getOnError();
this.onComplete = builder.getOnComplete();
}
/**
*
*/
public static OnCompleteAction builder() {
return new Builder();
}
public interface OnCompleteAction {
onErrorAction onComplete(#NonNull final Action onComplete);
}
public interface onErrorAction {
DoLoginRefreshFail onError(#NonNull final Consumer<? super Throwable> onError);
}
public interface DoLoginRefreshFail {
Build doLoginRefreshFail(#NonNull final Action doLoginRefreshFail);
}
public interface Build {
ExampleSequence build();
}
#SuppressLint("CheckResult")
public void execute() {
final AtomicInteger retryCounter = new AtomicInteger(0);
final Observable<Response<GraphqlQueryResponse>> feedArticles = getPageAndNextInboxArticles(offset, limit)
.onErrorResumeNext(manufactureResumeNext())
.subscribeOn(Schedulers.io());
final Observable<Response<GraphqlQueryResponse>> readingListArticles = getPageAndReadingListArticles(readingListoffset, limit)
.onErrorResumeNext(manufactureResumeNext())
.subscribeOn(Schedulers.io());
login()
.flatMap(...)
.ignoreElement()
.andThen(...)
.andThen(...)
.ignoreElements()
.andThen(...)
.flattenAsObservable(x -> x)
.flatMapCompletable(...)
.retryWhen(errors -> errors.flatMap(e -> constructRetryHandler(retryCounter, e)))
.doOnComplete(onComplete)
.doOnError(onError)
.doAfterTerminate(doAfterTerminate())
.doOnSubscribe(compositeDisposable::add)
.blockingAwait();
}
/**********************************************************************************
*
* BUILDER
*
*/
public static class Builder implements OnCompleteAction, onErrorAction, DoLoginRefreshFail, Build {
private Action onComplete;
private Consumer<? super Throwable> onError;
private Action doLoginRefreshFail;
/***********************************************************************
*
*/
#Override
public ExampleSequence build() {
return new ExampleSequence(this);
}
#Override
public onErrorAction onComplete(#NonNull final Action onComplete) {
this.onComplete = onComplete;
return this;
}
#Override
public DoLoginRefreshFail onError(#NonNull final Consumer<? super Throwable> onError) {
this.onError = onError;
return this;
}
#Override
public Build doLoginRefreshFail(#NonNull final Action doLoginRefreshFail) {
this.doLoginRefreshFail = doLoginRefreshFail;
return this;
}
/**
* #return the onError
*/
Consumer<? super Throwable> getOnError() {
return onError;
}
/**
* #return the onComplete
*/
Action getOnComplete() {
return onComplete;
}
Action getDoLoginRefreshFail() {
return doLoginRefreshFail;
}
}
}
The step builder pattern in Kotlin is completely doable, and I've provided an example of it that mirrors the Java example you provided.
class ExampleSequence private constructor(builder: Builder): Sequence(builder.doLoginRefreshFail) { //This is your "super()" call.
//This is equivalent to assigning the final variables [onComplete] and [onError] in the class constructor
private val onComplete = builder.onComplete
private val onError = builder.onError
//More info about companion objects here: https://kotlinlang.org/docs/reference/object-declarations.html#companion-objects
companion object {
//Java will see this as [ExampleSequence.Companion.builder()] unless you add this annotation
#JvmStatic
fun builder(): OnCompleteAction = Builder()
}
fun execute() {
//Do your stuff here...
}
//The following classes and interfaces are similar to being static inner classes. If you want the classes to access
//fields of the enclosing outer class, you must use the keyword [inner] before declaring the class. Example:
// inner class Foo { ... }
interface OnCompleteAction {
fun onComplete(onComplete: Action): onErrorAction
}
interface DoLoginRefreshFail {
fun doLoginRefreshFail(doLoginRefreshFail: Action): Build
}
interface onErrorAction {
fun onError(onError: Consumer<in Throwable>): DoLoginRefreshFail //The [in] keyword is the same as saying Consumer<? super Throwable>
}
interface Build {
fun build(): ExampleSequence
}
class Builder: OnCompleteAction, onErrorAction, DoLoginRefreshFail, Build {
//The [lateinit] keyword states that this variable will be initialized later. Calling it before it is initialized will throw an exception
lateinit var onComplete: Action
private set //Only this class can modify.
lateinit var onError: Consumer<in Throwable>
private set
lateinit var doLoginRefreshFail: Action
private set
//No special differences here... oooh, inlined [override] keyword!
override fun onComplete(onComplete: Action): onErrorAction {
this.onComplete = onComplete
return this
}
override fun doLoginRefreshFail(doLoginRefreshFail: Action): Build {
this.doLoginRefreshFail = doLoginRefreshFail
return this
}
override fun onError(onError: Consumer<in Throwable>): DoLoginRefreshFail {
this.onError = onError
return this
}
override fun build(): ExampleSequence = ExampleSequence(this)
//Where are the getter methods? If you look at the variable declarations, they are public by default.
//This means that these variables are public read, but can only be set by this class only. In other words, built-in getter!
}
}
However, in a pure Kotlin project, step builder is sort of an anti-pattern. With default and named parameters built into the language, you can actually achieve SOLID by a simple data class. Taking the ExampleSequence class for example, your solution could look something like:
data class ExampleSequence(
private val onComplete: Action,
private val onError: Consumer<in Throwable>,
private val doLoginRefreshFail: Action,
private val aNewParam: String = "Default")
: Sequence(doLoginRefreshFail) { //This is your "super()" call.
fun execute() {
//Do your stuff here...
}
}
fun foo() {
//Example of using named parameters and passing in variables. Notice parameters aren't in the same order as how it is declared in the class
ExampleSequence(
onError = Consumer(),
onComplete = Action(),
doLoginRefreshFail = Action()
).execute()
//Since I added [aNewParam], instead of using the default, let's change it.
ExampleSequence(
onError = Consumer(),
onComplete = Action(),
doLoginRefreshFail = Action(),
aNewParam = "Something else!"
).execute()
}
Here is a nice article going into a bit more detail: https://dev.to/chrisvasqm/avoiding-the-builder-design-pattern-in-kotlin-3b1a
Also, in case you need another example of a step builder pattern in Kotlin, you might want to check this out too: https://www.baeldung.com/kotlin-builder-pattern
I'm trying to write a lint rule to catch places where the result of an RxJava2 function is not used in anyway. For example:
final Observable<String> observable = getObservable();
observable.subscribe(this::onSuccess, this::onError);
In RxJava2, the subscribe function returns a Disposable that should be used to unsubscribe if the program/class instance "finishes" in some way in order to prevent memory leaks. I want to fail my build if any occurences like this are found.
This particular method (and all of the other ones I'm interested in) is annotated with io.reactivex.annotations.CheckReturnValue:
#CheckReturnValue
#SchedulerSupport(SchedulerSupport.NONE)
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {
return subscribe(onNext, onError, Functions.EMPTY_ACTION, Functions.emptyConsumer());
}
My plan is to write a custom lint rule that:
Searches for expressions that return the result of a method annotated with io.reactivex.annotations.CheckReturnValue
Filter the searches down to only expressions whose result is never used
For example, here are some cases that should not fail:
final CompositeDisposable compositeDisposable = new CompositeDisposable();
// Result of subscribe passed into another function
compositeDisposable.add(observable.subscribe(this::onSuccess, this::onError).dispose());
// Result of subscribe stored in a variable
final Disposable disposable = observable.subscribe(this::onSuccess, this::onError);
// Result of subscribe used
observable.subscribe(this::onSuccess, this::onError).dispose();
I've managed to write a lint rule that finds instances of call expressions where the result is annotated with CheckReturnValue, but I'm struggling to figure out how to use the JetBrains UAST/PSI APIs to work out if the result is used. This is my rule so far:
class RxJava2CheckReturnValueMethodNotAssigned : Detector(), Detector.UastScanner {
override fun getApplicableUastTypes() = listOf(UCallExpression::class.java)
override fun createUastHandler(context: JavaContext) = CheckReturnValueVisitor(context)
class CheckReturnValueVisitor(private val context: JavaContext) : UElementHandler() {
override fun visitCallExpression(node: UCallExpression) {
val method = node.resolve() ?: return
if (!isCheckReturnValueAnnotatedMethod(method)) {
return
}
if (!isResultOfCallUsed(node)) {
return
}
reportIssue(node)
}
private fun isCheckReturnValueAnnotatedMethod(method: PsiMethod): Boolean {
return context.evaluator.getAllAnnotations(method, true)
.any { "io.reactivex.annotations.CheckReturnValue" == it.qualifiedName }
}
private fun isResultOfCallUsed(node: UCallExpression): Boolean {
// Need to check is the result of the expression is used in some way
return false
}
private fun reportIssue(node: UCallExpression) {
// SNIP...
}
}
}
This currently doesn't work because it reports all usages of any function annotated with CheckReturnValue.
As far as I know, node.resolve() often return null
I'm new to writing tests and using Mockito.
I've read the similar topics here on Stackoverflow and made the suggested changes, making sure that regarded classes / interfaces / methods are open.
I tried to follow this
Mocking the constructor injected dependencies
This is the test I came up with so far
class RegistrationPresenterTest {
#Test
fun testRegisterSuccess() {
val mockService = mock<IHerokuInteractor>()
val mockLocal = mock<ILocalStorageInteractor>()
val mockView = mock<RegisterView>()
val mockRegistrationResponse = HerokuRegisterResponse("hash")
val mockPair = ImeiPair("imei","hash")
val presenter = RegisterPresenterImpl(mockLocal,mockService)
whenever(mockService.register(any())).thenReturn(Observable.just(mockRegistrationResponse))
whenever(mockLocal.clearPreferences()).thenReturn(Observable.just(true))
whenever(mockLocal.putImeiPair(any())).thenReturn(Observable.just(true))
//whenever(presenter.writeImeiPairLocally(any())) How do I specify parameters since it uses a parameter from the register method?
presenter.bindView(mockView)
presenter.register("imei","male")
verify(mockService, times(1)).register(any())
verify(mockLocal,times(1)).clearPreferences()
verify(mockLocal,times(1)).putImeiPair(any())
verify(mockView,times(1)).moveToMain()
}
but the response I keep getting is
Wanted but not invoked:
registerPresenterImpl.writeImeiPairLocally(
<any com.company.appname.model.ImeiPair>
);
Actually, there were zero interactions with this mock.
I got this response even when I don't mention that method in the test.
This is my presenter register method. I've changed the classes / interfaces & methods involved to open (kotlin). I believe override methods are open by nature in kotlin.
open class RegisterPresenterImpl #Inject constructor(val localStorage : ILocalStorageInteractor, var herokuService : IHerokuInteractor)
override fun register(imei : String, gender : String){
subscription = herokuService.register(RegisterObject(imei,gender)).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe(
{
registrationResult ->
Log.d(TAG,"${registrationResult}")
if(registrationResult.imei_hash != null){
writeImeiPairLocally(ImeiPair(imei,registrationResult.imei_hash))
}
else{
Log.e(TAG,"User already exists")
}
},
{
errorResponse -> Log.e(TAG,"Could not register user ${errorResponse.message}")
}
)
addSubscription(subscription)
}
and similarly the
open fun writeImeiPairLocally(pair : ImeiPair){
subscription = localStorage.clearPreferences().flatMap {
cleared -> localStorage.putImeiPair(pair)}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe(
{
booleanResult -> view?.moveToMain()
},
{
errorResponse -> Log.e(TAG,"Could not write ImeiPair to SharedPreferences ${errorResponse.message}")
}
)
addSubscription(subscription)
}
Here is interfaces
open interface ILocalStorageInteractor : ILocalStorage{
fun getImeiPair() : Observable<ImeiPair>
fun putImeiPair(pair: ImeiPair) : Observable<Boolean>
}
open interface ILocalStorage {
fun clearPreferences() : Observable<Boolean>
}
All help is appreciated.
If you are using plain jUnit, then your AndroidSchedulers.mainThread() is null. That's why onNext is not called.
You need to override Schedulers in a setUp() method with:
RxAndroidPlugins.getInstance().registerSchedulersHook(new RxAndroidSchedulersHook() {
#Override
public Scheduler getMainThreadScheduler() {
return Schedulers.immediate(); // or .test()
}
});
To avoid concurrency in tests, I would recommend to override Schedulers.io() like this:
RxJavaHooks.setOnIOScheduler(scheduler1 -> Schedulers.immediate());
If you are going to use TestScheduler, don't forget to call TestScheduler.triggerActions() method.
Also don't forget to unregister Schedulers in tearDown() like this:
RxJavaHooks.reset();
RxAndroidPlugins.getInstance().reset();
AndroidSchedulers.reset();
Schedulers.reset();
I am trying to test my ViewModel in my application, here is the constructor:
#Inject
public SearchUserViewModel(#Named("searchUser") UseCase searchUserUseCase) {
this.searchUserUseCase = searchUserUseCase;
}
In my test I create a SearchUserUseCase with mocks like this:
Observable error = Observable.error(new Throwable("Error"));
when(gitHubService.searchUser(MockFactory.TEST_USERNAME_ERROR)).thenReturn(error);
when(ObserverThread.getScheduler()).thenReturn(Schedulers.immediate());
when(SubscriberThread.getScheduler()).thenReturn(Schedulers.immediate());
searchUserUseCase = new SearchUserUseCase(gitHubService, SubscriberThread, ObserverThread);
In my ViewModel class I have this snippet which I want to test:
public void onClickSearch(View view) {
loadUsers();
}
private void loadUsers() {
if (username == null) {
fragmentListener.showMessage("Enter a username");
} else {
showProgressIndicator(true);
searchUserUseCase.execute(new SearchUserSubscriber(), username);
}
}
private final class SearchUserSubscriber extends DefaultSubscriber<SearchResponse> {
#Override
public void onCompleted() {
showProgressIndicator(false);
}
#Override
public void onError(Throwable e) {
showProgressIndicator(false);
fragmentListener.showMessage("Error loading users");
}
#Override
public void onNext(SearchResponse searchResponse) {
List<User> users = searchResponse.getUsers();
if (users.isEmpty()) {
fragmentListener.showMessage("No users found");
} else {
fragmentListener.addUsers(users);
}
}
}
Finally in my test I have this:
#Test
public void shouldDisplayErrorMessageIfErrorWhenLoadingUsers() {
SearchUserViewModel searchUserViewModel = new SearchUserViewModel(searchUserUseCase);
searchUserViewModel.setFragmentListener(mockFragmentListener);
searchUserViewModel.setUsername(MockFactory.TEST_USERNAME_ERROR);
searchUserViewModel.onClickSearch(view);
verify(mockFragmentListener).showMessage("Error loading users");
}
I get this error from Mockito:
Wanted but not invoked:
fragmentListener.showMessage(
"Error loading users"
);
I am not sure if this is a good test, but I somehow want to test the SearchUserSubscriber one way or another. Thanks
Edit: I have found similar questions to this problem here: Can't verify mock method call from RxJava Subscriber (which still isn't answered) and here: Verify interactions in rxjava subscribers. The latter question is similar but does not execute the subscriber in a separate class (which happens in SearchUserUseCase here).
I also tried RobolectricGradleTestRunner instead of MockitoJunitRunner and changed to Schedulers.io() and AndroidSchedulers.mainThread(), but I still get the same error.
Tried mocking SearchUserUseCase instead of GitHubService (which feels cleaner), but I'm not sure on how to test the subscriber that way since that is passed as an argument to the void method execute() in UseCase.
public void execute(Subscriber useCaseSubscriber, String query) {
subscription = buildUseCase(query)
.observeOn(postExecutionThread.getScheduler())
.subscribeOn(threadExecutor.getScheduler())
.subscribe(useCaseSubscriber);
}
And buildUseCase()
#Override
public Observable buildUseCase(String username) throws NullPointerException {
if (username == null) {
throw new NullPointerException("Query must not be null");
}
return getGitHubService().searchUser(username);
}
For me it worked out to add a Observable.Transformer<T, T> as followed:
void gatherData() {
service.doSomeMagic()
.compose(getSchedulerTransformer())
.subscribe(view::displayValue);
}
private <T> Observable.Transformer<T, T> getSchedulerTransformer() {
if (mTransformer == null) {
mTransformer = (Observable.Transformer<T, T>) observable -> observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
return mTransformer;
}
void setSchedulerTransformer(Observable.Transformer<Observable<?>, Observable<?>> transformer) {
mTransformer = transformer;
}
And to set the Transformer. I just passed this:
setSchedulerTransformer(observable -> {
if (observable instanceof Observable) {
Observable observable1 = (Observable) observable;
return observable1.subscribeOn(Schedulers.immediate())
.observeOn(Schedulers.immediate());
}
return null;
});
So just add a #Before method in your test and call presenter.setSchedulerTransformer and it should be able to test this. If you want more detail check this answer.
If you are using Mockito, you can probably get hold of a SearchUserSubscriber using an ArgumentCaptor, for example...
#Captor
private ArgumentCaptor<SearchUserSubscriber> subscriberCaptor;
private SearchUserSubscriber getSearchUserSubscriber() {
// TODO: ...set up the view model...
...
// Execute the code under test (making sure the line 'searchUserUseCase.execute(new SearchUserSubscriber(), username);' gets hit...)
viewModel.onClickSearch(view);
verify(searchUserUseCase).execute(subscriberCaptor.capture(), any(String.class));
return subscriberCaptor.getValue();
}
Now you can have test cases such as...
#Test
public void shouldDoSomethingWithTheSubscriber() {
SearchUserSubscriber subscriber = getSearchUserSubscriber();
...
}