// Path: src/main/java/two/davincing/DaVincing.java
// @Mod(modid = DaVincing.MOD_ID, name = DaVincing.MOD_NAME, version = DaVincing.MOD_VERSION)
// public class DaVincing {
// 
//   /* Global logger that uses string format type logging */
//   public static final Logger log = LogManager.getLogger(DaVincing.class.getSimpleName(), new StringFormatterMessageFactory());
//   /* Task scheduler for background task. Will run at lowest thread priority to not interfere with FPS/ticks */
//   public static final ScheduledExecutorService backgroundTasks = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), new PriorityThreadFactory(DaVincing.class.getSimpleName() + " Worker", Thread.MIN_PRIORITY, true));
//   public static final ConcurrentLinkedQueue<Runnable> glTasks = new ConcurrentLinkedQueue<Runnable>();
//   
//   public static final String MOD_NAME = "DaVincing";
//   public static final String MOD_ID = "davincing";
//   public static final String MOD_VERSION = "1710.1.8"; // Make sure to keep this version in sync with the build.gradle file!
// 
//   @Mod.Instance(MOD_ID)
//   public static DaVincing instance; // this will point to the actual instance of this class once running
// 
//   @SidedProxy(clientSide = "two.davincing.ProxyClient", serverSide = "two.davincing.ProxyServer")
//   public static ProxyBase proxy; // will load the appropriate proxy class depending whether this is running on a client or on a server
// 
//   public static final Config config = new Config();
//   public static final CreativeTabs tabDaVincing = new DaVincingCreativeTab();
//   public static final SimpleNetworkWrapper network = NetworkRegistry.INSTANCE.newSimpleChannel("minepainter");
// 
//   @Mod.EventHandler
//   public void preInit(FMLPreInitializationEvent event) {
//     config.initialize(event.getSuggestedConfigurationFile());
//     proxy.onPreInit();
//   }
// 
//   @Mod.EventHandler
//   public void init(FMLInitializationEvent e) {
//     config.load();
//     proxy.onInit();
// 
//     Crafting.instance.registerRecipes();
// 
//     network.registerMessage(SculptureOperationMessage.SculptureOperationHandler.class, SculptureOperationMessage.class, 0, Side.SERVER);
//     network.registerMessage(PaintingOperationHandler.class, PaintingOperationMessage.class, 1, Side.SERVER);
//     config.save();
//   }
// 
//   @Mod.EventHandler
//   public void postInit(final FMLPostInitializationEvent event) {
//     proxy.onPostInit();
//   }
// 
//   @Mod.EventHandler
//   public void serverLoad(final FMLServerStartingEvent event) {
//     event.registerServerCommand(new CommandImportPainting());
//   }
// 
//   @Mod.EventHandler
//   public void serverStopped(final FMLServerStoppedEvent event) {
//   }
// }


import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import two.davincing.DaVincing;
package two.davincing.utils;


public abstract class ExpirablePool<K, V> implements Runnable {

  static final long DEFAULT_CHECK_INTERVAL_MS = 80;
  static final long DEFAULT_EXPIRY_TIME_MS = 60 * 1000;

  protected final class MapEntry<V> {

    final V value;
    long expireDate = 0;

    public MapEntry(final V value) {
      this.value = value;
    }

    public void updateExpiry() {
      this.expireDate = System.currentTimeMillis() + DEFAULT_EXPIRY_TIME_MS;
    }
  }

  protected final ConcurrentHashMap<K, MapEntry<V>> items = new ConcurrentHashMap<K, MapEntry<V>>();
  protected ScheduledFuture<?> cleanupTask = null;

  public ExpirablePool() {
  }

  protected abstract void release(final V value);

  protected abstract V create(final K key);

  public void start() {
    if (cleanupTask == null) {
// Path: src/main/java/two/davincing/DaVincing.java
// @Mod(modid = DaVincing.MOD_ID, name = DaVincing.MOD_NAME, version = DaVincing.MOD_VERSION)
// public class DaVincing {
// 
//   /* Global logger that uses string format type logging */
//   public static final Logger log = LogManager.getLogger(DaVincing.class.getSimpleName(), new StringFormatterMessageFactory());
//   /* Task scheduler for background task. Will run at lowest thread priority to not interfere with FPS/ticks */
//   public static final ScheduledExecutorService backgroundTasks = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), new PriorityThreadFactory(DaVincing.class.getSimpleName() + " Worker", Thread.MIN_PRIORITY, true));
//   public static final ConcurrentLinkedQueue<Runnable> glTasks = new ConcurrentLinkedQueue<Runnable>();
//   
//   public static final String MOD_NAME = "DaVincing";
//   public static final String MOD_ID = "davincing";
//   public static final String MOD_VERSION = "1710.1.8"; // Make sure to keep this version in sync with the build.gradle file!
// 
//   @Mod.Instance(MOD_ID)
//   public static DaVincing instance; // this will point to the actual instance of this class once running
// 
//   @SidedProxy(clientSide = "two.davincing.ProxyClient", serverSide = "two.davincing.ProxyServer")
//   public static ProxyBase proxy; // will load the appropriate proxy class depending whether this is running on a client or on a server
// 
//   public static final Config config = new Config();
//   public static final CreativeTabs tabDaVincing = new DaVincingCreativeTab();
//   public static final SimpleNetworkWrapper network = NetworkRegistry.INSTANCE.newSimpleChannel("minepainter");
// 
//   @Mod.EventHandler
//   public void preInit(FMLPreInitializationEvent event) {
//     config.initialize(event.getSuggestedConfigurationFile());
//     proxy.onPreInit();
//   }
// 
//   @Mod.EventHandler
//   public void init(FMLInitializationEvent e) {
//     config.load();
//     proxy.onInit();
// 
//     Crafting.instance.registerRecipes();
// 
//     network.registerMessage(SculptureOperationMessage.SculptureOperationHandler.class, SculptureOperationMessage.class, 0, Side.SERVER);
//     network.registerMessage(PaintingOperationHandler.class, PaintingOperationMessage.class, 1, Side.SERVER);
//     config.save();
//   }
// 
//   @Mod.EventHandler
//   public void postInit(final FMLPostInitializationEvent event) {
//     proxy.onPostInit();
//   }
// 
//   @Mod.EventHandler
//   public void serverLoad(final FMLServerStartingEvent event) {
//     event.registerServerCommand(new CommandImportPainting());
//   }
// 
//   @Mod.EventHandler
//   public void serverStopped(final FMLServerStoppedEvent event) {
//   }
// }


// Path: src/main/java/two/davincing/utils/ExpirablePool.java
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import two.davincing.DaVincing;

package two.davincing.utils;


public abstract class ExpirablePool<K, V> implements Runnable {

  static final long DEFAULT_CHECK_INTERVAL_MS = 80;
  static final long DEFAULT_EXPIRY_TIME_MS = 60 * 1000;

  protected final class MapEntry<V> {

    final V value;
    long expireDate = 0;

    public MapEntry(final V value) {
      this.value = value;
    }

    public void updateExpiry() {
      this.expireDate = System.currentTimeMillis() + DEFAULT_EXPIRY_TIME_MS;
    }
  }

  protected final ConcurrentHashMap<K, MapEntry<V>> items = new ConcurrentHashMap<K, MapEntry<V>>();
  protected ScheduledFuture<?> cleanupTask = null;

  public ExpirablePool() {
  }

  protected abstract void release(final V value);

  protected abstract V create(final K key);

  public void start() {
    if (cleanupTask == null) {
      cleanupTask = DaVincing.backgroundTasks.scheduleAtFixedRate(this, 0, DEFAULT_CHECK_INTERVAL_MS, TimeUnit.MILLISECONDS);