// Path: src/protocolsupportpocketstuff/libs/jodah/expiringmap/internal/Assert.java
// public final class Assert {
//   private Assert() {
//   }
// 
//   public static <T> T notNull(T reference, String parameterName) {
//     if (reference == null)
//       throw new NullPointerException(parameterName + " cannot be null");
//     return reference;
//   }
// 
//   public static void operation(boolean condition, String message) {
//     if (!condition)
//       throw new UnsupportedOperationException(message);
//   }
// 
//   public static void state(boolean expression, String errorMessageFormat, Object... args) {
//     if (!expression)
//       throw new IllegalStateException(String.format(errorMessageFormat, args));
//   }
// 
//   public static void element(Object element, Object key) {
//     if (element == null)
//       throw new NoSuchElementException(key.toString());
//   }
// }
// 
// Path: src/protocolsupportpocketstuff/libs/jodah/expiringmap/internal/NamedThreadFactory.java
// public class NamedThreadFactory implements ThreadFactory {
//   private final AtomicInteger threadNumber = new AtomicInteger(1);
//   private final String nameFormat;
// 
//   /**
//    * Creates a thread factory that names threads according to the {@code nameFormat} by supplying a
//    * single argument to the format representing the thread number.
//    */
//   public NamedThreadFactory(String nameFormat) {
//     this.nameFormat = nameFormat;
//   }
// 
//   @Override
//   public Thread newThread(Runnable r) {
//     Thread thread = new Thread(r, String.format(nameFormat, threadNumber.getAndIncrement()));
//     thread.setDaemon(true);
//     return thread;
//   }
// }


import protocolsupportpocketstuff.libs.jodah.expiringmap.internal.Assert;
import protocolsupportpocketstuff.libs.jodah.expiringmap.internal.NamedThreadFactory;
import java.lang.ref.WeakReference;
import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
   * Adds an expiration listener.
   * 
   * @param listener to add
   * @throws NullPointerException if {@code listener} is null
   */
  public synchronized void addExpirationListener(ExpirationListener<K, V> listener) {
    Assert.notNull(listener, "listener");
    if (expirationListeners == null)
      expirationListeners = new CopyOnWriteArrayList<ExpirationListener<K, V>>();
    expirationListeners.add(listener);
  }

  /**
   * Adds an asynchronous expiration listener.
   * 
   * @param listener to add
   * @throws NullPointerException if {@code listener} is null
   */
  public synchronized void addAsyncExpirationListener(ExpirationListener<K, V> listener) {
    Assert.notNull(listener, "listener");
    if (asyncExpirationListeners == null)
      asyncExpirationListeners = new CopyOnWriteArrayList<ExpirationListener<K, V>>();
    asyncExpirationListeners.add(listener);
  }

  @Override
  public void clear() {
    writeLock.lock();
    try {
      for (ExpiringEntry<K, V> entry : entries.values())
// Path: src/protocolsupportpocketstuff/libs/jodah/expiringmap/internal/Assert.java
// public final class Assert {
//   private Assert() {
//   }
// 
//   public static <T> T notNull(T reference, String parameterName) {
//     if (reference == null)
//       throw new NullPointerException(parameterName + " cannot be null");
//     return reference;
//   }
// 
//   public static void operation(boolean condition, String message) {
//     if (!condition)
//       throw new UnsupportedOperationException(message);
//   }
// 
//   public static void state(boolean expression, String errorMessageFormat, Object... args) {
//     if (!expression)
//       throw new IllegalStateException(String.format(errorMessageFormat, args));
//   }
// 
//   public static void element(Object element, Object key) {
//     if (element == null)
//       throw new NoSuchElementException(key.toString());
//   }
// }
// 
// Path: src/protocolsupportpocketstuff/libs/jodah/expiringmap/internal/NamedThreadFactory.java
// public class NamedThreadFactory implements ThreadFactory {
//   private final AtomicInteger threadNumber = new AtomicInteger(1);
//   private final String nameFormat;
// 
//   /**
//    * Creates a thread factory that names threads according to the {@code nameFormat} by supplying a
//    * single argument to the format representing the thread number.
//    */
//   public NamedThreadFactory(String nameFormat) {
//     this.nameFormat = nameFormat;
//   }
// 
//   @Override
//   public Thread newThread(Runnable r) {
//     Thread thread = new Thread(r, String.format(nameFormat, threadNumber.getAndIncrement()));
//     thread.setDaemon(true);
//     return thread;
//   }
// }


// Path: src/protocolsupportpocketstuff/libs/jodah/expiringmap/ExpiringMap.java
import protocolsupportpocketstuff.libs.jodah.expiringmap.internal.Assert;
import protocolsupportpocketstuff.libs.jodah.expiringmap.internal.NamedThreadFactory;
import java.lang.ref.WeakReference;
import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

   * Adds an expiration listener.
   * 
   * @param listener to add
   * @throws NullPointerException if {@code listener} is null
   */
  public synchronized void addExpirationListener(ExpirationListener<K, V> listener) {
    Assert.notNull(listener, "listener");
    if (expirationListeners == null)
      expirationListeners = new CopyOnWriteArrayList<ExpirationListener<K, V>>();
    expirationListeners.add(listener);
  }

  /**
   * Adds an asynchronous expiration listener.
   * 
   * @param listener to add
   * @throws NullPointerException if {@code listener} is null
   */
  public synchronized void addAsyncExpirationListener(ExpirationListener<K, V> listener) {
    Assert.notNull(listener, "listener");
    if (asyncExpirationListeners == null)
      asyncExpirationListeners = new CopyOnWriteArrayList<ExpirationListener<K, V>>();
    asyncExpirationListeners.add(listener);
  }

  @Override
  public void clear() {
    writeLock.lock();
    try {
      for (ExpiringEntry<K, V> entry : entries.values())
        entry.cancel();