// Path: rainbow-lib/src/main/java/com/juankysoriano/rainbow/utils/schedulers/RainbowScheduler.java
// public class RainbowScheduler {
//     private final ScheduledExecutorService scheduler;
//     private boolean running;
// 
//     RainbowScheduler(ScheduledExecutorService scheduler) {
//         this.scheduler = scheduler;
//     }
// 
//     public void scheduleNow(Runnable runnable) {
//         scheduler.schedule(runnable, 0, TimeUnit.MILLISECONDS);
//     }
// 
//     public void scheduleAtRate(Runnable runnable, long delay, TimeUnit timeUnit) {
//         running = true;
//         scheduler.scheduleAtFixedRate(runnable, 0, delay, timeUnit);
//     }
// 
//     public boolean isTerminated() {
//         return !running;
//     }
// 
//     public void shutdown() {
//         scheduler.shutdownNow();
//         running = false;
//     }
// 
// }
// 
// Path: rainbow-lib/src/main/java/com/juankysoriano/rainbow/utils/schedulers/RainbowSchedulers.java
// public abstract class RainbowSchedulers {
//     public static RainbowScheduler single(String name, Priority priority) {
//         ThreadFactory threadFactory = RainbowThreadFactory.newInstance(name, priority.threadPriority);
//         return new RainbowScheduler(Executors.newScheduledThreadPool(1, threadFactory));
//     }
// 
//     /**
//      * The stack size for the threads on this scheduler is enough to perform long recursion tasks
//      **/
//     public static RainbowScheduler singleForRecursion(String name, Priority priority) {
//         ThreadFactory threadFactory = RainbowThreadFactory.newInstanceForRecursion(name, priority.threadPriority);
//         return new RainbowScheduler(Executors.newScheduledThreadPool(1, threadFactory));
//     }
// 
//     public static RainbowScheduler multiThreaded(String name, Priority priority) {
//         ThreadFactory threadFactory = RainbowThreadFactory.newInstance(name, priority.threadPriority);
//         return new RainbowScheduler(Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors() * 2, threadFactory));
//     }
// 
//     public static RainbowScheduler multiThreaded(String name, Priority priority, int threads) {
//         ThreadFactory threadFactory = RainbowThreadFactory.newInstance(name, priority.threadPriority);
//         return new RainbowScheduler(Executors.newScheduledThreadPool(threads, threadFactory));
//     }
// 
//     /**
//      * The stack size for the threads on this scheduler is enough to perform long recursion tasks
//      **/
//     public static RainbowScheduler multiThreadedForRecursion(String name, Priority priority) {
//         ThreadFactory threadFactory = RainbowThreadFactory.newInstanceForRecursion(name, priority.threadPriority);
//         return new RainbowScheduler(Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors() * 2, threadFactory));
//     }
// 
//     public enum Priority {
//         MAX(Thread.MAX_PRIORITY),
//         NORMAL(Thread.NORM_PRIORITY),
//         MIN(Thread.MIN_PRIORITY);
// 
//         private int threadPriority;
// 
//         Priority(int threadPriority) {
//             this.threadPriority = threadPriority;
//         }
//     }
// }


import com.juankysoriano.rainbow.utils.schedulers.RainbowScheduler;
import com.juankysoriano.rainbow.utils.schedulers.RainbowSchedulers;
import java.util.concurrent.TimeUnit;
            }
        });
    }

    void scheduleDrawing(int stepRate, int frameRate, int inputRate) {
        screenScheduler().scheduleAtRate(stepTask, SECOND / stepRate, TimeUnit.NANOSECONDS);
        screenScheduler().scheduleAtRate(invalidateTask, SECOND / frameRate, TimeUnit.NANOSECONDS);
        inputScheduler().scheduleAtRate(inputTask, SECOND / inputRate, TimeUnit.NANOSECONDS);
    }

    boolean isTerminated() {
        return screenScheduler().isTerminated() || inputScheduler().isTerminated();

    }

    void shutdown() {
        stepTask.shutdown();
        invalidateTask.shutdown();
        inputTask.shutdown();
        screenScheduler().shutdown();
        inputScheduler().shutdown();
    }

    private RainbowScheduler screenScheduler() {
        if (screenScheduler == null || screenScheduler.isTerminated()) {
            screenScheduler = RainbowSchedulers.single("Drawing", RainbowSchedulers.Priority.MAX);
        }
        return screenScheduler;
    }

// Path: rainbow-lib/src/main/java/com/juankysoriano/rainbow/utils/schedulers/RainbowScheduler.java
// public class RainbowScheduler {
//     private final ScheduledExecutorService scheduler;
//     private boolean running;
// 
//     RainbowScheduler(ScheduledExecutorService scheduler) {
//         this.scheduler = scheduler;
//     }
// 
//     public void scheduleNow(Runnable runnable) {
//         scheduler.schedule(runnable, 0, TimeUnit.MILLISECONDS);
//     }
// 
//     public void scheduleAtRate(Runnable runnable, long delay, TimeUnit timeUnit) {
//         running = true;
//         scheduler.scheduleAtFixedRate(runnable, 0, delay, timeUnit);
//     }
// 
//     public boolean isTerminated() {
//         return !running;
//     }
// 
//     public void shutdown() {
//         scheduler.shutdownNow();
//         running = false;
//     }
// 
// }
// 
// Path: rainbow-lib/src/main/java/com/juankysoriano/rainbow/utils/schedulers/RainbowSchedulers.java
// public abstract class RainbowSchedulers {
//     public static RainbowScheduler single(String name, Priority priority) {
//         ThreadFactory threadFactory = RainbowThreadFactory.newInstance(name, priority.threadPriority);
//         return new RainbowScheduler(Executors.newScheduledThreadPool(1, threadFactory));
//     }
// 
//     /**
//      * The stack size for the threads on this scheduler is enough to perform long recursion tasks
//      **/
//     public static RainbowScheduler singleForRecursion(String name, Priority priority) {
//         ThreadFactory threadFactory = RainbowThreadFactory.newInstanceForRecursion(name, priority.threadPriority);
//         return new RainbowScheduler(Executors.newScheduledThreadPool(1, threadFactory));
//     }
// 
//     public static RainbowScheduler multiThreaded(String name, Priority priority) {
//         ThreadFactory threadFactory = RainbowThreadFactory.newInstance(name, priority.threadPriority);
//         return new RainbowScheduler(Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors() * 2, threadFactory));
//     }
// 
//     public static RainbowScheduler multiThreaded(String name, Priority priority, int threads) {
//         ThreadFactory threadFactory = RainbowThreadFactory.newInstance(name, priority.threadPriority);
//         return new RainbowScheduler(Executors.newScheduledThreadPool(threads, threadFactory));
//     }
// 
//     /**
//      * The stack size for the threads on this scheduler is enough to perform long recursion tasks
//      **/
//     public static RainbowScheduler multiThreadedForRecursion(String name, Priority priority) {
//         ThreadFactory threadFactory = RainbowThreadFactory.newInstanceForRecursion(name, priority.threadPriority);
//         return new RainbowScheduler(Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors() * 2, threadFactory));
//     }
// 
//     public enum Priority {
//         MAX(Thread.MAX_PRIORITY),
//         NORMAL(Thread.NORM_PRIORITY),
//         MIN(Thread.MIN_PRIORITY);
// 
//         private int threadPriority;
// 
//         Priority(int threadPriority) {
//             this.threadPriority = threadPriority;
//         }
//     }
// }


// Path: rainbow-lib/src/main/java/com/juankysoriano/rainbow/core/RainbowTaskScheduler.java
import com.juankysoriano.rainbow.utils.schedulers.RainbowScheduler;
import com.juankysoriano.rainbow.utils.schedulers.RainbowSchedulers;
import java.util.concurrent.TimeUnit;

            }
        });
    }

    void scheduleDrawing(int stepRate, int frameRate, int inputRate) {
        screenScheduler().scheduleAtRate(stepTask, SECOND / stepRate, TimeUnit.NANOSECONDS);
        screenScheduler().scheduleAtRate(invalidateTask, SECOND / frameRate, TimeUnit.NANOSECONDS);
        inputScheduler().scheduleAtRate(inputTask, SECOND / inputRate, TimeUnit.NANOSECONDS);
    }

    boolean isTerminated() {
        return screenScheduler().isTerminated() || inputScheduler().isTerminated();

    }

    void shutdown() {
        stepTask.shutdown();
        invalidateTask.shutdown();
        inputTask.shutdown();
        screenScheduler().shutdown();
        inputScheduler().shutdown();
    }

    private RainbowScheduler screenScheduler() {
        if (screenScheduler == null || screenScheduler.isTerminated()) {
            screenScheduler = RainbowSchedulers.single("Drawing", RainbowSchedulers.Priority.MAX);
        }
        return screenScheduler;
    }

    private RainbowScheduler inputScheduler() {