Mariusz Sieroń 6 år sedan
förälder
incheckning
2864f01faa

+ 80 - 9
assira/src/main/java/net/ranides/assira/events/EventDispatcher.java

@@ -7,11 +7,8 @@
 package net.ranides.assira.events;
 
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+
 import net.ranides.assira.collection.maps.HashMap;
 import net.ranides.assira.trace.LoggerUtils;
 import net.ranides.assira.trace.ThreadUtils;
@@ -31,6 +28,8 @@ import org.slf4j.Logger;
  */
 public class EventDispatcher implements EventRouter {
 
+    public static EventDispatcher NULL = new EmptyDispatcher();
+
     private static final Logger LOGGER = LoggerUtils.getLogger();
     
     private static final Map<String, WeakReference<EventDispatcher>> DISPATCHERS = new HashMap<>();
@@ -51,8 +50,16 @@ public class EventDispatcher implements EventRouter {
     }
     
     public static EventDispatcher find(String name) {
-        WeakReference<EventDispatcher> ref = DISPATCHERS.get(name);
-        return null!=ref ? ref.get() : null;
+        synchronized (DISPATCHERS) {
+            WeakReference<EventDispatcher> ref = DISPATCHERS.get(name);
+            if(ref != null) {
+                EventDispatcher found = ref.get();
+                if(found != null) {
+                    return found;
+                }
+            }
+            return EventDispatcher.NULL;
+        }
     }
 
     @Override
@@ -250,7 +257,9 @@ public class EventDispatcher implements EventRouter {
         // signal update
         synchronized(this) {
             this.listeners = null;
-            DISPATCHERS.remove(name());
+            synchronized (DISPATCHERS) {
+                DISPATCHERS.remove(name());
+            }
         }
     }
 
@@ -258,5 +267,67 @@ public class EventDispatcher implements EventRouter {
     public void dispose() {
         dispose(true);
     }
-    
+
+    private static class EmptyDispatcher extends EventDispatcher {
+        @Override
+        public String name() {
+            return "$null";
+        }
+
+        @Override
+        public <T extends Event> void addEventListener(Class<T> event, EventListener<? super T> listener) {
+            // do nothing
+        }
+
+        @Override
+        public <T extends Event> void removeEventListener(Class<T> event, EventListener<? super T> listener) {
+            // do nothing
+        }
+
+        @Override
+        public void removeAllEventListeners() {
+            // do nothing
+        }
+
+        @Override
+        public Collection<EventBinding<?>> getEventListeners() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public int getEventListenersCount() {
+            return 0;
+        }
+
+        @Override
+        public boolean signalEvent(Event event) {
+            return false;
+        }
+
+        @Override
+        public void dispose() {
+            // do nothing
+        }
+
+        @Override
+        public void handleEvent(Event event) {
+            // do nothing
+        }
+
+        @Override
+        protected void dispatchEvent(Event event) {
+            // do nothing
+        }
+
+        @Override
+        protected void dispatchEvent(Event event, boolean direct) {
+            // do nothing
+        }
+
+        @Override
+        protected <T extends Event> void dispatchEvent(EventListener<? super T> listener, T event) {
+            // do nothing
+        }
+
+    }
 }

+ 5 - 3
assira/src/main/java/net/ranides/assira/events/EventHandler.java

@@ -21,10 +21,12 @@ import java.lang.annotation.Target;
 @Documented
 public @interface EventHandler {
     
-    String UI = "awt";
-    
-    String UI_WAIT = "awt:wait";
+    String UI = "$awt";
     
+    String UI_WAIT = "$awt:wait";
+
+    String TIMER = "$timer";
+
     String router() default "";
     
 }

+ 23 - 3
assira/src/main/java/net/ranides/assira/events/EventObserver.java

@@ -7,11 +7,13 @@
 package net.ranides.assira.events;
 
 import java.util.List;
+
 import net.ranides.assira.awt.AWTInvoker;
 import net.ranides.assira.functional.VarFunction;
 import net.ranides.assira.reflection.IAttribute;
 import net.ranides.assira.reflection.IClass;
 import net.ranides.assira.reflection.IMethod;
+import net.ranides.assira.time.TimerInvoker;
 
 /**
  *
@@ -44,11 +46,13 @@ public class EventObserver implements EventListener<Event> {
         String router = info.router();
         switch(router) {
             case "":
-                return new THandler(type, m.bind(delegator));
+                return new ThisHandler(type, m.bind(delegator));
             case EventHandler.UI:
                 return new UIHandler(type, false, m.bind(delegator));
             case EventHandler.UI_WAIT:
                 return new UIHandler(type, true, m.bind(delegator));
+            case EventHandler.TIMER:
+                return new TimerHandler(type, m.bind(delegator));
             default:
                 return new NHandler(router, type, m.bind(delegator));
         }
@@ -80,11 +84,11 @@ public class EventObserver implements EventListener<Event> {
         
     }
     
-    private static final class THandler extends IHandler {
+    private static final class ThisHandler extends IHandler {
         
         private final VarFunction<?> handle;
 
-        public THandler(IClass<?> type, VarFunction<?> handle) {
+        public ThisHandler(IClass<?> type, VarFunction<?> handle) {
             super(type);
             this.handle = handle;
         }
@@ -95,6 +99,22 @@ public class EventObserver implements EventListener<Event> {
         }
         
     }
+
+    private static final class TimerHandler extends IHandler {
+
+        private final VarFunction<?> handle;
+
+        public TimerHandler(IClass<?> type, VarFunction<?> handle) {
+            super(type);
+            this.handle = handle;
+        }
+
+        @Override
+        public void call(Event event) {
+            TimerInvoker.later(0, () -> handle.call(event));
+        }
+
+    }
     
     private static final class UIHandler extends IHandler {
         

+ 11 - 0
assira/src/main/java/net/ranides/assira/functional/Cancelable.java

@@ -0,0 +1,11 @@
+package net.ranides.assira.functional;
+
+public interface Cancelable extends Runnable {
+
+    boolean cancel();
+
+    boolean isDone();
+
+    boolean isCanceled();
+
+}

+ 284 - 0
assira/src/main/java/net/ranides/assira/time/TaskScheduler.java

@@ -0,0 +1,284 @@
+package net.ranides.assira.time;
+
+import net.ranides.assira.awt.AWTInvoker;
+import net.ranides.assira.events.Event;
+import net.ranides.assira.events.EventDispatcher;
+import net.ranides.assira.events.EventHandler;
+import net.ranides.assira.events.EventRouter;
+
+import java.time.Duration;
+import java.util.TimerTask;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.RunnableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+public class TaskScheduler {
+
+    private EventRouter router;
+
+    private String routerName;
+
+    private Duration delay;
+
+    private Duration interval;
+
+    private Integer repeat;
+
+    private Consumer<Integer> actionInterval;
+
+    private Consumer<Integer> actionStart;
+
+    private Consumer<Integer> actionFinish;
+
+    private Consumer<Integer> actionCancel;
+
+    private Function<Integer, Event> eventInterval;
+
+    private Function<Integer, Event> eventStart;
+
+    private Function<Integer, Event> eventFinish;
+
+    private Function<Integer, Event> eventCancel;
+
+    public TaskScheduler() {
+        // do nothing
+    }
+
+    public TaskScheduler router(EventRouter router) {
+        this.router = router;
+        return this;
+    }
+
+    public TaskScheduler router(String router) {
+        this.routerName = router;
+        return this;
+    }
+
+    public TaskScheduler delay(long millis) {
+        return delay(Duration.ofMillis(millis));
+    }
+
+    public TaskScheduler delay(Duration duration) {
+        this.delay = duration;
+        return this;
+    }
+
+    public TaskScheduler interval(long interval) {
+        return interval(Duration.ofMillis(interval));
+    }
+
+    public TaskScheduler interval(Duration interval) {
+        this.interval = interval;
+        return this;
+    }
+
+    public TaskScheduler repeat(int repeat) {
+        this.repeat = repeat;
+        return this;
+    }
+
+    public TaskScheduler start(Runnable action) {
+        this.actionStart = (v) -> action.run();
+        return this;
+    }
+
+    public TaskScheduler start(Supplier<Event> action) {
+        this.eventStart = (v) -> action.get();
+        return this;
+    }
+
+    public TaskScheduler finish(Runnable action) {
+        this.actionFinish = (v) -> action.run();
+        return this;
+    }
+
+    public TaskScheduler finish(Supplier<Event> action) {
+        this.eventFinish = (v) -> action.get();
+        return this;
+    }
+
+    public TaskScheduler interval(Consumer<Integer> action) {
+        this.actionInterval = action;
+        return this;
+    }
+
+    public TaskScheduler interval(Runnable action) {
+        this.actionInterval = (v) -> action.run();
+        return this;
+    }
+
+    public TaskScheduler interval(Function<Integer, Event> action) {
+        this.eventInterval = action;
+        return this;
+    }
+
+    public TaskScheduler interval(Supplier<Event> action) {
+        this.eventInterval = (v) -> action.get();
+        return this;
+    }
+
+    public TaskScheduler cancel(Runnable action) {
+        this.actionCancel = (v) -> action.run();
+        return this;
+    }
+
+    public TaskScheduler cancel(Supplier<Event> action) {
+        this.eventCancel = (v) -> action.get();
+        return this;
+    }
+
+    public TimerTask build() {
+
+        initRouter();
+
+        actionStart = initDispatch(actionStart, eventStart);
+        actionCancel = initDispatch(actionCancel, eventCancel);
+        actionInterval = initDispatch(actionInterval, eventInterval);
+        actionFinish = initDispatch(actionFinish, eventFinish);
+
+        initIntervalStart();
+
+        boolean awt = EventHandler.UI.equals(routerName) || EventHandler.UI_WAIT.equals(routerName);
+        boolean snc = EventHandler.UI_WAIT.equals(routerName);
+        if(awt) {
+            actionStart = initUI(actionStart, snc);
+            actionFinish = initUI(actionFinish, snc);
+            actionCancel = initUI(actionCancel, snc);
+            actionInterval = initUI(actionInterval, snc);
+        }
+
+        return newTimer();
+    }
+
+    private void initRouter() {
+        if(routerName != null) {
+            if(router != null) {
+                throw new IllegalStateException("Both router and router name is specified in invoker");
+            }
+            router = EventDispatcher.find(routerName);
+        }
+    }
+
+    private Consumer<Integer> initDispatch(Consumer<Integer> action, Function<Integer, Event> event) {
+        if(event == null) {
+            return action;
+        }
+        if(action != null) {
+            throw new IllegalStateException("Both action and event supplier is specified in invoker");
+        }
+        if(router == EventDispatcher.NULL) {
+            throw new IllegalStateException("Event supplier is defined, but event dispatcher not");
+        }
+        return (v) -> router.signalEvent( event.apply(v) );
+    }
+
+    private void initIntervalStart() {
+        if(interval == null) {
+            if(actionInterval != null) {
+                throw new IllegalStateException("Task has defined repeat interval but not interval action");
+            }
+            if(actionStart != null && actionFinish != null) {
+                actionStart = (v) -> { actionStart.accept(v); actionFinish.accept(v); };
+            }
+        }
+    }
+
+    private static Consumer<Integer> initUI(Consumer<Integer> action, boolean sync) {
+        if(action == null) {
+            return null;
+        }
+        return (v) -> AWTInvoker.run(sync, () -> action.accept(v));
+    }
+
+    private TimerTask newTimer() {
+        if(actionInterval != null) {
+            Integer max = initMax();
+            return TimerInvoker.repeat(toMillis(delay), toMillis(interval), new IntervalTask(max, actionStart, actionCancel, actionFinish, actionInterval));
+        } else {
+            return TimerInvoker.later(toMillis(delay), new LaterTask(actionStart, actionCancel));
+        }
+    }
+
+    private Integer initMax() {
+        if(repeat == null) {
+            return null;
+        }
+        return repeat + (actionStart !=null ? 1 : 0) + (actionFinish !=null ? 1 : 0);
+    }
+
+    private static long toMillis(Duration duration) {
+        return duration!=null ? duration.toMillis() : 0;
+    }
+
+    private static class LaterTask extends TimerTask {
+
+        protected final Consumer<Integer> rStart;
+
+        protected final Consumer<Integer> rCancel;
+
+        public LaterTask(Consumer<Integer> rStart, Consumer<Integer> rCancel) {
+            this.rStart = rStart;
+            this.rCancel = rCancel;
+        }
+
+        @Override
+        public void run() {
+            rStart.accept(0);
+        }
+
+        @Override
+        public boolean cancel() {
+            if(super.cancel()) {
+                if(rCancel!=null) {
+                    rCancel.accept(0);
+                }
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+    }
+
+    private static class IntervalTask extends LaterTask {
+
+        private final AtomicInteger counter = new AtomicInteger(0);
+
+        private final Integer max;
+
+        protected final Consumer<Integer> rFinish;
+
+        protected final Consumer<Integer> rInterval;
+
+        public IntervalTask(Integer max, Consumer<Integer> rStart, Consumer<Integer> rCancel, Consumer<Integer> rFinish, Consumer<Integer> rInterval) {
+            super(rStart, rCancel);
+            this.max = max;
+            this.rFinish = rFinish;
+            this.rInterval = rInterval;
+        }
+
+        @Override
+        public void run() {
+            int now = counter.getAndIncrement();
+            if(now == 0 && rStart!=null) {
+                rStart.accept(0);
+                return;
+            }
+            if(max != null && now > max) {
+                super.cancel();
+                if(rFinish != null) {
+                    rFinish.accept(now);
+                }
+                return;
+            }
+            rInterval.accept(rStart!=null ? now-1 : now);
+        }
+
+    }
+
+}

+ 116 - 0
assira/src/main/java/net/ranides/assira/time/TimerInvoker.java

@@ -0,0 +1,116 @@
+package net.ranides.assira.time;
+
+import lombok.experimental.UtilityClass;
+import net.ranides.assira.functional.Cancelable;
+
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.atomic.AtomicReference;
+
+@UtilityClass
+public class TimerInvoker {
+
+    static final class Li {
+
+        static final Timer TIMER = new Timer("Assira TimerUtils", true);
+
+    }
+
+    public static TimerTask later(long delay, Runnable action) {
+        return later(delay, asTimerTask(action));
+    }
+
+    public static TimerTask later(long delay, TimerTask task) {
+        Li.TIMER.schedule(task, delay);
+        return task;
+    }
+
+    public static TimerTask repeat(long delay, long period, Runnable action) {
+        return repeat(delay, period, asTimerTask(action));
+    }
+
+    public static TimerTask repeat(long delay, long period, TimerTask task) {
+        Li.TIMER.schedule(task, delay, period);
+        return task;
+    }
+
+    public static Cancelable lazy(long delay, Runnable action) {
+        return new LazyCancelable(delay, action);
+    }
+
+    private static TimerTask asTimerTask(Runnable action) {
+        return new TimerTask() {
+            @Override
+            public void run() {
+                action.run();
+            }
+        };
+    }
+
+    private static class LazyCancelable implements Cancelable {
+
+        private final AtomicReference<TimerTask> task = new AtomicReference<>();
+
+        private volatile boolean finished;
+
+        private volatile boolean canceled;
+
+        private final long delay;
+
+        private final Runnable action;
+
+        public LazyCancelable(long delay, Runnable action) {
+            this.delay = delay;
+            this.action = action;
+        }
+
+        @Override
+        public void run() {
+            task.getAndUpdate(prev -> {
+                if(prev != null) {
+                    prev.cancel();
+                }
+                this.canceled = false;
+                this.finished = false;
+                return later(delay, this::call);
+            });
+        }
+
+        private void call() {
+            try {
+                action.run();
+            } finally {
+                task.set(null);
+                finished = true;
+                canceled = true;
+            }
+        }
+
+        @Override
+        public boolean cancel() {
+            if(this.canceled || this.finished) {
+                return false;
+            }
+            task.getAndUpdate(prev -> {
+                if(prev != null) {
+                    prev.cancel();
+                    this.canceled = true;
+                    this.finished = false;
+                }
+                return null;
+            });
+            return true;
+        }
+
+        @Override
+        public boolean isDone() {
+            return this.finished;
+        }
+
+        @Override
+        public boolean isCanceled() {
+            return this.canceled;
+        }
+    }
+
+}

+ 0 - 31
assira1/src/main/java/net/ranides/assira/time/AutoTimerFrame.java

@@ -1,31 +0,0 @@
-/*
- *  @author Ranides Atterwim <ranides@gmail.com>
- *  @copyright Ranides Atterwim
- *  @license WTFPL
- *  @url http://ranides.net/projects/assira
- */
-
-package net.ranides.assira.time;
-
-/**
- *
- * @author ranides
- * @todo (migration) assira
- */
-public abstract class AutoTimerFrame<T> extends AutoTimerTask<T> {
-
-    @Override
-    public AutoTimerFrame<T> cancel() {
-        if(handle != null) {
-            handle.cancel();
-            canceled(this.param);
-            handle = null;
-        }
-        return this;
-    }
-
-    public abstract void started(T param);
-    public abstract void finished(T param);
-    public abstract void canceled(T param);
-
-}

+ 0 - 98
assira1/src/main/java/net/ranides/assira/time/AutoTimerTask.java

@@ -1,98 +0,0 @@
-/*
- *  @author Ranides Atterwim <ranides@gmail.com>
- *  @copyright Ranides Atterwim
- *  @license WTFPL
- *  @url http://ranides.net/projects/assira
- */
-
-package net.ranides.assira.time;
-import java.util.TimerTask;
-import javax.swing.SwingUtilities;
-
-/**
- *
- * @author ranides
- * @todo (migration) assira
- */
-public abstract class AutoTimerTask<T> {
-
-    /*package*/ TimerTask handle;
-    /*package*/ T param;
-
-    public abstract void run(T param, int now, int max);
-    
-    public AutoTimerTask<T> cancel() {
-        if(handle != null) {
-            handle.cancel(); 
-            handle = null;
-        }
-        return this;
-    }
-    
-    public boolean active() {
-        return handle != null;
-    }
-    
-    protected AutoTimerTask<T> apply(boolean sync, int steps, T param) {
-        this.handle =  sync ? new AwtHandler<>(this, steps) : new TaskHandler<>(this, steps);
-        this.param = param;
-        return this;
-    }
-    
-    protected AutoTimerTask<T> schedule(int delay) {
-        TimeUtils.Li.TIMER.schedule( handle, 0, delay );
-        return this;
-    }
-    
-    
-    
-    private static class AwtHandler<Q> extends TaskHandler<Q> {
-
-        public AwtHandler(AutoTimerTask<Q> action, int max) {
-            super(action, max);
-        }
-        
-        private final Runnable runner = new Runnable() {
-            @Override
-            public void run() {
-                AwtHandler.super.run();
-            }
-        };
-        
-        @Override
-        public void run() {
-            SwingUtilities.invokeLater(runner);
-        }
-    }
-    
-    private static class TaskHandler<Q> extends TimerTask {
-        
-        private final AutoTimerTask<Q> action;
-        private final int max;
-        private int now;
-        
-
-        public TaskHandler(AutoTimerTask<Q> action, int max) {
-            this.action = action;
-            this.now = 0;
-            this.max = max;
-        }
-
-        @Override
-        public void run() {
-            if (now >= max) {
-                if (action instanceof AutoTimerFrame) {
-                    ((AutoTimerFrame<Q>)action).finished(action.param);
-                }
-                cancel();
-            } else {
-                if (0 == now && action instanceof AutoTimerFrame) {
-                    ((AutoTimerFrame<Q>) action).started(action.param);
-                } else {
-                    action.run(action.param, now, max);
-                }
-                now++;
-            }
-        }
-    }
-}

+ 0 - 50
assira1/src/main/java/net/ranides/assira/time/LazyInvoker.java

@@ -1,50 +0,0 @@
-/*
- * @author Ranides Atterwim <ranides@gmail.com>
- * @copyright Ranides Atterwim
- * @license WTFPL
- * @url http://ranides.net/projects/assira
- */
-package net.ranides.assira.time;
-
-import java.util.TimerTask;
-
-/**
- * Użycie:
- * <pre>
- *   {@code LazyInvoker action = new LazyInvoker(true, 1000) { 
- *      public void run() {
- *        // action ...
- *      }
- *   };}</pre>
- * Następnie np w "onKeyPress" kolejkujemy wykonanie:
- * <pre>
- *  {@code action.runLazy() }</pre>
- * 
- * Mimo, że {@link #runLazy} może być wywoływane wielokrotnie w odstępach 
- * {@code t<1000}, to {@link #run} uruchomi się tylko raz, {@code 1000}ms 
- * po ostatnim wywołaniu {@link #runLazy}.
- * 
- * @author ranides
- * @todo (migration) assira
- */
-public abstract class LazyInvoker implements Runnable {
-    
-    private TimerTask task;
-    private final int delay;
-    private final boolean awt;
-
-    public LazyInvoker(boolean awt, int delay) {
-        this.delay = delay;
-        this.awt = awt;
-    }
-        
-    public void runLazy() {
-        synchronized(this) {
-            if (task != null) {
-                task.cancel();
-            }
-            task = awt ? TimeUtils.runAfterUI(delay, this) : TimeUtils.runAfter(delay, this);
-        }
-    }
-
-}

+ 0 - 117
assira1/src/main/java/net/ranides/assira/time/TimeUtils.java

@@ -1,117 +0,0 @@
-/*
- *  @author Ranides Atterwim <ranides@gmail.com>
- *  @copyright Ranides Atterwim
- *  @license WTFPL
- *  @url http://ranides.net/projects/assira
- */
-
-package net.ranides.assira.time;
-
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-import java.util.Timer;
-import java.util.TimerTask;
-import javax.swing.SwingUtilities;
-import net.ranides.assira.trace.ExceptionInspector;
-
-/**
- *
- * @author ranides
- * @todo (migration) assira
- */
-@SuppressWarnings({"PMD.ShortVar"})
-public final class TimeUtils {
-
-    private TimeUtils() { }
-
-    public static final long SECOND   = 1000;
-    public static final long MINUTE   = 60 * SECOND;
-    public static final long HOUR     = 60 * MINUTE;
-    public static final long DAY      = 24 * HOUR;
-
-    public static long diff(Date from, Date to) {
-        return to.getTime() - from.getTime();
-    }
-
-    public static float diff(Date from, Date to, long unit) {
-        return ( to.getTime() - from.getTime() ) / (float)unit;
-    }
-
-    public static void sleep(int ms) {
-        try {
-            Thread.sleep(ms);
-        } catch (InterruptedException cause) {
-            throw ExceptionInspector.rethrow(cause);
-        }
-    }
-
-    public static String format(Date date, String format, String ddefault) {
-        if(null == date) {
-            return ddefault;
-        }
-        return new SimpleDateFormat(format, Locale.ROOT).format(date);
-    }
-
-    /**
-     * Use caliper library instead
-     * @param repeats
-     * @param function
-     * @return
-     * @deprecated
-     */
-    @Deprecated
-    public static TimeResult benchmark(int repeats, Runnable function) {
-        TimeStack timer = new TimeStack();
-        Runnable empty = new Runnable(){ @Override public void run() { /* do nothing */ } };
-
-        timer.start();
-        for(int i=0; i<repeats; i++) { empty.run(); }
-        long t1 = timer.stop();
-
-        timer.start();
-        for(int i=0; i<repeats; i++) { function.run(); }
-        long t2 = timer.stop();
-
-        return new TimeResult(repeats, t1, t2);
-    }
-    
-    public static TimerTask runAfterUI(int ms, final TimerTask action) {
-        return runAfterUI(ms, new Runnable() {
-            @Override
-            public void run() { action.run(); }
-        });
-    }
-    
-    public static TimerTask runAfterUI(int ms, final Runnable action) {
-        return runAfter(ms, new Runnable(){
-            @Override
-            public void run() { SwingUtilities.invokeLater(action); }
-        });
-    }
-    
-    public static TimerTask runAfter(int ms, final Runnable action) {
-        return runAfter(ms, new TimerTask() { 
-            @Override
-            public void run() { action.run(); } 
-        });
-    }
-
-    public static TimerTask runAfter(int ms, TimerTask action) {
-        Li.TIMER.schedule(action, ms);
-        return action;
-    }
-    
-    public static <Q> AutoTimerTask<Q> runRepeat(int count, int delay, Q param, AutoTimerTask<Q> task) {
-        return task.apply(false, count, param).schedule(delay);
-    }
-    
-    public static <Q> AutoTimerTask<Q> runRepeatUI(int count, int delay, Q param, AutoTimerTask<Q> task) {
-        return task.apply(true, count, param).schedule(delay);
-    }
-    
-    static final class Li { // NOPMD - lazy init idiom
-        static final Timer TIMER = new Timer("Assira TimeUtils",true);
-    }
-
-}