I wrote an application that runs some threads using ExecutorService and waits until they finish like this:
ExecutorService exService;
exService = Executors.newCachedThreadPool();
exService.execute(T1);
exService.execute(T2);
exService.shutdown();
boolean finshed = exService.awaitTermination(5, TimeUnit.MINUTES);
sometimes I need to cancel the execution of these threads (The entire ExecutorService).
I tried exService.shutdownNow() but it throws java.lang.InterruptedException and doesn't cancel threads.
How can I cancel execution of these threads?
EDIT: T1 class code added as nanda's request
public class TC implements Runnable{
private ExtractedDataBuffer Buffer;
private Scraper scraper;
private String AppPath;
private boolean Succeed=false;
private Map<String,Object> Result=null;
private JLabel StatElement;
public TC(ExtractedDataBuffer Buffer,String AppPath,String XMLfile,JLabel Stat) throws FileNotFoundException {
this.Buffer = Buffer;
this.AppPath=AppPath;
this.StatElement=Stat;
ScraperConfiguration config;
config = new ScraperConfiguration(AppPath + Main.XMLFilesPath +XMLfile);
scraper = new Scraper(config, AppPath);
}
private void extract(){
try{
mainF.SetIconStat("working", this.StatElement);
scraper.execute();
if(scraper.getStatus()==Scraper.STATUS_FINISHED){
this.Succeed=true;
Map<String,Object> tmp=new HashMap<String,Object>();
tmp.put("UpdateTime", ((Variable) scraper.getContext().get("UpdateTime")).toString().trim());
Buffer.setVal(this.Result);
mainF.SetIconStat("done", this.StatElement);
}else{
this.Succeed=false;
this.Result=null;
Buffer.setVal(null);
mainF.SetIconStat("error", this.StatElement);
}
}catch(Exception ex){
this.Succeed=false;
this.Result=null;
Buffer.setVal(null);
mainF.SetIconStat("error", this.StatElement);
}
}
public void run() {
this.extract();
}
}
If you change shutdown() to shutdownNow(), you are doing the correct thing in the code that you wrote. But then, check the documentation of shutdownNow():
There are no guarantees beyond best-effort attempts to stop processing
actively executing tasks. For example, typical implementations will
cancel via Thread.interrupt(), so any task that fails to respond to
interrupts may never terminate.
So probably your T1 and T2 are not coded in a correct way and don't respond to the interrupt well enough. Can you maybe copy the code for them?
--
Based on your code, I guess the code that takes long time is scraper.execute(), right? So inside those method, you have to constantly check something like this:
if (Thread.interrupted()) {
throw new InterruptedException();
}
If the interrupt come, the InterruptedException will be thrown and catched in your catch statement and the thread will stop.
My problem with Future#cancel() is that subsequent calls to get() throw a CancellationException. Sometimes I still want be able to call get() on the Future in order to retrieve a partial result after the shutdown of the executor service. In that case one can implement the termination logic in the callables that you submit to the executor service. Use a field like
private volatile boolean terminate;
public void terminate() {
terminate = true;
}
and check for terminate in the callable as often as required. In addition, you have to remember your callables somewhere so you can call terminate() on all of them.
Use the Executor.submit method, it extends base method Executor.execute(java.lang.Runnable) by creating and returning a Future that can be used to cancel execution and/or wait for completion:
task = Executor.submit( T1 )
...
task.cancel( true )
Related
I am calling some service that returns a response thru some callback function.
I used thread to call this service so that it is running in its own process.
The thread is called in my Main thread.
My question is how can I optimize my busy while loop in calling this service.
Sometimes the service fails and it is okay to just continue to retry looping in until a good response is received.
public class ProcessResponse extends Thread
boolean isOK = false;
public void responseReturned(Response response){
//more code
if(response.OK){
//process result
isOK = true;
}
}
public void run(){
while(true){
// call service
Thread.sleep(1000);
if(isOK)
break;
}
}
}
UPDATE 2:
My next line of thinking is just to use latch
public class ProcessResponse extends Thread
boolean isOK = false;
CountDownLatch latch = new CountDownLatch(1);
public void responseReturned(Response response){
//more code
if(response.OK){
//process result
isOK = true;
}
latch.countDown();
}
public void run(){
while(!isOK){
// call service
try {
latch.await();
} catch (InterruptedException e) {
//handle interruption
}
latch = new CountDownLatch(1);
}
}
}
There is no sleep command but I am not sure if reinitializing the latch is a good approach. The service sometimes takes time to return.
Note..I haven't tried this code yet.. I just type it in so I am not sure if this will work.
There are lot of options that are fortunately available in JAVA 5 which you can use:
1) Cyclic Barrier:
Create a cyclic barrier of 2 and as the responseReturned will be called through main thread, you can simply put cyclic barrier await function to implement this. It has advantage that you can reuse the same barrier again and again without need to reinialize it.
2) CountDown Latch
Create a countdown latch of 1 and as soon as the responseReturned call the countdown function of latch, the await function in run will allow it to move ahead. It has a disadvantage that you have to reinitialize latch in case you want to reuse it.
3) ExecutorService
You can also use ExecutorService and can call future object get method to wait till proper response is returned.
4) Semaphore You can also use aquire before calling the service and release it in responseReturned. In run you can again call aquire post call to wait till response is returned.
All of them will allow you to implement the functionality with almost similar efficiency.
Hope that helps.
Future interface may be used for these kind of interactions along with ExecutorService I guees. Once you submit a request ,you can set the timeout for the callback etc.
Future<String> futureTask = executorService.submit(callable);
String result = null;
try {
result = futureTask.get(500, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
e.printStackTrace();
}
I am performing some operations that are time sensitive and have a timeout associated with them.
This timeout mechanism is implemented using the Java Callable class.
The problem is that within the callable instance I execute an asynchronous task, with an anonymous interface implementation (listener).
My problem is that when the timeout triggers and the callable is cancelled. The async callback still executes and corrupts the state of my program.
How do I prevent these callbacks from firing? Do I just include a boolean specififying whether or not the timeout has ocurred or is there another way of achieving this please?
Thanks.
Code reference:
Callable<Object> callableTransaction = new Callable<Object>() {
#Override
public Object call() throws Exception {
Callback callback = new Callback() {
// Do stuff here and change program state.
};
performAsyncOperation(callback);
return ActionProcessor.OPERATION_COMPLETE;
}
};
Why don't you remove performAsyncOperation and perform the operation synchronously inside the call method.
And then, if you need any async operation, you can invoke your callableTransaction using performAsyncOperation or executor services.
Wrap your Callable in a java.util.concurrent.FutureTask... call task.cancel(true) when you want to cancel things. If your Callable is in a blocking operation (I/O, for example), then an exception will be thrown marking the interruption. Otherwise, your thread will need to check using Thread.isInterrupted() periodically to see if it should continue or abort.
Yes, this is mostly the same as including your own boolean flag, but you do get the benefit of blocking operations getting interrupted as well.
You have the right idea: Use a boolean flag to track whether the Callable has been interrupted. (I'm assuming that when you cancel the Callable, you are specifying that it should be interrupted.)
Use a concurrent class like CountDownLatch to make your Callable behave synchronously:
public Object call() throws Exception {
final AtomicBoolean aborted = new AtomicBoolean();
final CountDownLatch latch = new CountDownLatch(1);
Callback callback = new Callback() {
if (aborted.get()) {
return;
}
// Do stuff here and change program state.
latch.countDown(); // Tell Callable we're done.
};
performAsyncOperation(callback);
try {
latch.await(); // Wait for callback to finish.
} catch (InterruptedException e) {
aborted.set(true);
}
return ActionProcessor.OPERATION_COMPLETE;
}
I am learning to use ExectorService to pool threads and send out tasks. I have a simple program below
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
class Processor implements Runnable {
private int id;
public Processor(int id) {
this.id = id;
}
public void run() {
System.out.println("Starting: " + id);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println("sorry, being interupted, good bye!");
System.out.println("Interrupted " + Thread.currentThread().getName());
e.printStackTrace();
}
System.out.println("Completed: " + id);
}
}
public class ExecutorExample {
public static void main(String[] args) {
Boolean isCompleted = false;
ExecutorService executor = Executors.newFixedThreadPool(2);
for (int i = 0; i < 5; i++) {
executor.execute(new Processor(i));
}
//executor does not accept any more tasks but the submitted tasks continue
executor.shutdown();
System.out.println("All tasks submitted.");
try {
//wait for the exectutor to terminate normally, which will return true
//if timeout happens, returns false, but this does NOT interrupt the threads
isCompleted = executor.awaitTermination(100, TimeUnit.SECONDS);
//this will interrupt thread it manages. catch the interrupted exception in the threads
//If not, threads will run forever and executor will never be able to shutdown.
executor.shutdownNow();
} catch (InterruptedException e) {
}
if (isCompleted) {
System.out.println("All tasks completed.");
} else {
System.out.println("Timeout " + Thread.currentThread().getName());
}
}
}
It does nothing fancy, but creates two threads and submits 5 tasks in total. After each thread completes its task, it takes the next one,
In the code above, I use executor.submit. I also changed to executor.execute. But I do not see any difference in the output. In what way are the submit and execute methods different?
This what the API says
Method submit extends base method Executor.execute(java.lang.Runnable) by creating and returning a Future that can be used to cancel execution and/or wait for completion. Methods invokeAny and invokeAll perform the most commonly useful forms of bulk execution, executing a collection of tasks and then waiting for at least one, or all, to complete. (Class ExecutorCompletionService can be used to write customized variants of these methods.)
But it's not clear to me as what it exactly means?
As you see from the JavaDoc execute(Runnable) does not return anything.
However, submit(Callable<T>) returns a Future object which allows a way for you to programatically cancel the running thread later as well as get the T that is returned when the Callable completes. See JavaDoc of Future for more details
Future<?> future = executor.submit(longRunningJob);
...
//long running job is taking too long
future.cancel(true);
Moreover,
if future.get() == null and doesn't throw any exception then Runnable executed successfully
The difference is that execute simply starts the task without any further ado, whereas submit returns a Future object to manage the task. You can do the following things with the Future object:
Cancel the task prematurely, with the cancel method.
Wait for the task to finish executing, with get.
The Future interface is more useful if you submit a Callable to the pool. The return value of the call method will be returned when you call Future.get. If you don't maintain a reference to the Future, there is no difference.
execute: Use it for fire and forget calls
submit: Use it to inspect the result of method call and take appropriate action on Future objected returned by the call
Major difference: Exception handling
submit() hides un-handled Exception in framework itself.
execute() throws un-handled Exception.
Solution for handling Exceptions with submit()
Wrap your Callable or Runnable code in try{} catch{} block
OR
Keep future.get() call in try{} catch{} block
OR
implement your own ThreadPoolExecutor and override afterExecute method
Regarding tour other queries on
invokeAll:
Executes the given tasks, returning a list of Futures holding their status and results when all complete or the timeout expires, whichever happens first.
invokeAny:
Executes the given tasks, returning the result of one that has completed successfully (i.e., without throwing an exception), if any do before the given timeout elapses.
Use invokeAll if you want to wait for all submitted tasks to complete.
Use invokeAny if you are looking for successful completion of one task out of N submitted tasks. In this case, tasks in progress will be cancelled if one of the tasks completes successfully.
Related post with code example:
Choose between ExecutorService's submit and ExecutorService's execute
A main difference between the submit() and execute() method is that ExecuterService.submit()can return result of computation because it has a return type of Future, but execute() method cannot return anything because it's return type is void. The core interface in Java 1.5's Executor framework is the Executor interface which defines the execute(Runnable task) method, whose primary purpose is to separate the task from its execution.
Any task submitted to Executor can be executed by the same thread, a worker thread from a thread pool or any other thread.
On the other hand, submit() method is defined in the ExecutorService interface which is a sub-interface of Executor and adds the functionality of terminating the thread pool, along with adding submit() method which can accept a Callable task and return a result of computation.
Similarities between the execute() and submit() as well:
Both submit() and execute() methods are used to submit a task to Executor framework for asynchronous execution.
Both submit() and execute() can accept a Runnable task.
You can access submit() and execute() from the ExecutorService interface because it also extends the Executor interface which declares the execute() method.
Apart from the fact that submit() method can return output and execute() cannot, following are other notable differences between these two key methods of Executor framework of Java 5.
The submit() can accept both Runnable and Callable task but execute() can only accept the Runnable task.
The submit() method is declared in ExecutorService interface while execute() method is declared in the Executor interface.
The return type of submit() method is a Future object but return type of execute() method is void.
If you check the source code, you will see that submit is sort of a wrapper on execute
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
Submit - Returns Future object, which can be used to check result of submitted task. Can be used to cancel or to check isDone etc.
Execute - doesn't return anything.
The execute(Runnable command) is the implemented method from Interface Executor. It means just execute the command and gets nothing returned.
ExecutorService has its own methods for starting tasks: submit, invokeAny and invokeAll all of which have Callable instances as their main targets. Though there're methods having Runnable as input, actulaly Runnable will be adapted to Callable in the method. why Callable? Because we can get a Future<T> result after the task is submitted.
But when you transform a Runnable to a Callable, result you get is just the value you pass:
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result;
}
}
So, what's the point that we pass a Runnable to submit instead of just getting the result when the task is finished? Because there's a method which has only Runnable as parameter without a particular result.
Read the javadoc of Future:
If you would like to use a Future for the sake of cancellability but not provide a usable result, you can declare types of the form Future<?> and return null as a result of the underlying task.
So, if you just want to execute a Runnable task without any value returned, you can use execute().
if you want to run a Callable task, or
if you want to run a Runnable task with a specified result as the completion symbol, or
if you want to run a task and have the ability to cancel it,
you should use submit().
On top of previous responses, i.e.
execute(..) runs the task and forget about it
submit(...) returns a future;
The main advantage with the future is that you can establish a timeout. This might come very handy if you have an executor with a limited number of threads and your executions are taking forever, it will not hang the process.
Example 1: hangs forever and fills the executor
ExecutorService executor = Executors.newFixedThreadPool(2);
for (int i=0; i < 5; i++) {
executor.execute(() -> {
while (true) {
System.out.println("Running...")
Thread.sleep(Long.MAX_VALUE)
}
});
}
Your output will be (i.e. only 2 and it gets stuck):
Running...
Running...
On the other hand, you can use submit and add a timeout:
ExecutorService executor = Executors.newFixedThreadPool(2);
for (int i=0; i < 5; i++) {
Future future = executor.submit(() -> {
while (true) {
System.out.println("Running...");
Thread.sleep(Long.MAX_VALUE);
}
});
try {
future.get(1, TimeUnit.SECONDS);
} catch (Exception e) {
if (!future.isDone()) {
System.out.println("Oops: " + e.getClass().getSimpleName());
future.cancel(true);
}
}
}
The output will look like this (notice that the executor does not get stuck, but you need to manually cancel the future):
Running...
Oops: TimeoutException
Running...
Oops: TimeoutException
Running...
Oops: TimeoutException
Running...
Oops: TimeoutException
Running...
Oops: TimeoutException
basically both calls execute,if u want future object you shall call submit() method
here from the doc
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
as you can see java really has no way to start a thread other than calling run() method, IMO. since i also found that Callable.call() method is called inside run() method. hence if the object is callable it would still call run() method, which inturn would call call() method
from doc.
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
I have a situation where I'm using a Thread, she call a method that will do multiple processes, I need to use a "cancel" button in which you have to stop the thread, I not can use: "while" ,to verify that it was canceled because it not has loop in this process.
Ex:
Task<Void> task = new Task<Void>() {
#Override
protected Void call() throws Exception {
controller = new FirstEtapaController();
execProcess();
return null;
}
};
new Thread(task).start();
Call Method
private void execProcess() {
Thread thread = new Thread(new Runnable() {
public void run() {
getController().execMhetod();
refreshTable();
}
});
thread.start();
thread.join();
};
Ie, I need to stop this process, even when the "ExecMethod" already running, it will take minutes, so I've gotta stop it and not have to wait for him to finish so that , others do not continues.
Remembering that this process will do iteration with my DAO.
The only way (well behaved way) is to add logic points in you spawned threads to check for an interrupted state. You can choose to use the built-in Thread.interrupt() mechanisms, or add your own logic using some form of thread-safe variable (an AtomicBoolean?) or a Semaphore of some sort.
If you use the Thread.interrupt() then your child processes will throw an InterruptedException when they encounter certain conditions, like Thread.wait() and other methods which require synchronization or use the java.util.concurrent.* classes.
You will need to (should already be) handle the InterruptedExceptions in the threads anyway, but perhaps you will need to put regular 'checks' in your child processes to look for the interrupted state anyway (can use Thread.isInterrupted() )
It is worth reading this Handling InterruptedException in Java
If instead of a raw Thread if you use an ExecutorService you'll end up with lots of additional methods/levers to control your threads, one of which is shutdownAll() which uses Thread.interrupt() to kill your thread and lets you check thread status via isTerminated()
Your user interface does not have to wait for the worker thread to finish, so don't worry too much about that.
Alas, Thread.destroy() and Thread.stop() are deprecated, due to bad implementations. I don't think there is a good "sig-kill" type of substitute for Java threads. You are going to have to recode the worker to check an abort flag of some kind, if it matters much. Otherwise, just let it waste a little CPU. ("you can't cancel that Save -- I've already done it!", in effect)
Whether or not a task can be canceled really depends on its implementation. Typically it intermittently checks a flag whether it should continue or not.
You can implement such a flag yourself, and a method to set it :
private volatile boolean shouldStop;
public void cancel() {
shouldStop = true;
}
#Override
public void run() {
while (!shouldStop) {
// do work
}
}
But threads already come with a flag : the interrupted flag. And while it is not necessarily used for canceling a thread, it is typical to use it for exactly that purpose. In fact the standard ExecutorService implementations will try to cancel their threads by interrupting them.
Aside from that several blocking methods (methods that put a thread in BLOCKED or WAITING state) will throw an InterruptedException when the thread is interrupted, at which point they become RUNNABLE again. This is something the previous approach with a boolean flag cannot achieve.
Therefore it is a better approach to use interruption to allow a task to be canceled. And you do not really need that cancel() method any more either :
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
// do work
}
}
As a bonus, any code that knows your thread, knows how to cancel it. Including standard ExecutorService implementations.
Care should be taken when catching an InterruptedException, since doing that clears the interrupted flag. It is adviseable to always restore the interrupted flag when catching the Exception, so clients also know it's time to stop doing what they're doing.
private BlockingQueue<Integer> queue;
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Integer id = queue.take(); // blocking method
// do work
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
To cancel a thread, you can simply keep a reference to the Thread object and call interrupt() on it :
Thread thread = new Thread(new InterruptibleTask());
thread.start();
// some time after :
thread.interrupt();
But a more elegant approach is keeping tabs on your task (and not so much the specific thread it runs on) through a Future object. You can do this by wrapping your Runnable or Callable in a FutureTask.
RunnableFuture<Void> task = new FutureTask<>(new InterruptibleTask(), null);
new Thread(task).start();
// some time after :
task.cancel(true); // true indicating interruption may be used to cancel.
A Future is key in controlling your task. It allows you to wait for its completion, and optionally receive a value the task calculated :
try {
String value = future.get(); // return value is generically typed String is just as example.
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // since future.get() blocks
} catch (ExecutionException e) {
logger.log(Level.SEVERE, "Exception on worker thread", e.getCause()); // the ExecutionException's cause is the Exception that occurred in the Task
}
If you have several tasks (or even just one) it is worth using an ExecutorService :
ExecutorService pool = Executors.newCachedThreadPool();
Future<?> submit = pool.submit(new InterruptibleTask());
pool.shutdownNow(); // depending on ExecutorService implementation this will cancel all tasks for you, the ones Executors returns do.
I have a processing loop of the form
while (true) {
doWork();
Thread.sleep(SLEEP_INTERVAL);
}
I want to make a Runnable out of this that can play well with ExecutorService and which will exit when ExecutorService.shutdownNow() is called.
I'm looking to write it this way:
public WorkerTask implements Runnable
{
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
doWork();
try {
Thread.sleep(SLEEP_INTERVAL);
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
Simple testing shows it at least appearing to work in that the task gets interrupted and will exit and the ExecutorService will shut down, and appears to do so whether the interrupt arrives while doWork() is processing or during the sleep. (By varying how much work doWork() does and how big SLEEP_INTERVAL is I can pretty much control where the interrupt happens).
But when I google I see examples using Thread.interrupted() as well as Thread.currentThread().isInterrupted(). I understand that the former clears the interrupted flag while the latter leaves it, but is there any other difference I need to care about?
I also see versions where the result of Thread.currentThread().isInterrupted() or Thread.interrupted() is stored in a volatile variable and that variable is used as the while loop test condition. Is that just a style or is there a need to do that? In what I've written do I have to worry that somehow something can clear the interrupt flag between when it is set (whether by being received when the thread is live, or by my catching InterruptedException and reasserting the flag) and when Thread.currentThread().isInterrupted() is called in the loop test?
Your code looks fine to me. Introducing an additional volatile variable would be unnecessary complexity: the interrupt status does the job.
The recommended way, in Java Concurrency in Practice, to deal with interrupts in tasks is to either throw an InterruptedException (this is doable if the task is a Callable and not a Runnable), or to make sure the interrupt status is set and to exit from the task ASAP. Your code does that well.
Could you take a look at ScheduledExecutorService if it matches your requirements:
class BeeperControl {
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
public void beepForAnHour() {
final Runnable beeper = new Runnable() {
public void run() { System.out.println("beep"); }
};
final ScheduledFuture<?> beeperHandle =
scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
scheduler.schedule(new Runnable() {
public void run() { beeperHandle.cancel(true); }
}, 60 * 60, SECONDS);
}
}}
Basically you should take advantage of java.util.concurrent libraries here .You should submit your task via ExecutorService.submit()and then call blocking methods like Future.get() , then you can be sure that those methods will respond to interruption as soon as possible by throwing an ExecutionException() .You probably should get rid of that Thread.sleep() since it is doing nothing . You want to sniff an interrupt as quickly as possible .You possibly also want to wait for a timeout in case your task is doing something inifinitely . So if the task terminates with a TimeOutException , the task is cancelled via its Future.
I call cancel() unconditionally since cancelling a completed task has no effect.
In that case you can do some thing like :
public static void main(String[] args) {
WorkerTask runnable;
TimeUnit unit;
Future<?> task = executor.submit(workerTask);
try{
task.get(timeout,unit);
} catch(TimeoutException e){
}catch(ExecutionException e){
throw e.getCause();
} finally{
//Harmless if the task already completed
task.cancel(true);
}
}
}