text:
package org.ehcache.xml;

import org.ehcache.config.CacheConfiguration;
import org.ehcache.config.Configuration;
import org.ehcache.config.EvictionAdvisor;
import org.ehcache.config.ResourcePool;
import org.ehcache.config.ResourcePools;
import org.ehcache.config.Builder;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheEventListenerConfigurationBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.builders.WriteBehindConfigurationBuilder;
import org.ehcache.config.builders.WriteBehindConfigurationBuilder.BatchedWriteBehindConfigurationBuilder;
import org.ehcache.core.internal.util.ClassLoading;
import org.ehcache.event.CacheEventListener;
import org.ehcache.event.EventFiring;
import org.ehcache.event.EventOrdering;
import org.ehcache.expiry.Duration;
import org.ehcache.expiry.Expirations;
import org.ehcache.expiry.Expiry;
import org.ehcache.impl.config.copy.DefaultCopierConfiguration;
import org.ehcache.impl.config.copy.DefaultCopyProviderConfiguration;
import org.ehcache.impl.config.event.CacheEventDispatcherFactoryConfiguration;
import org.ehcache.impl.config.event.DefaultCacheEventDispatcherConfiguration;
import org.ehcache.impl.config.executor.PooledExecutionServiceConfiguration;
import org.ehcache.impl.config.loaderwriter.DefaultCacheLoaderWriterConfiguration;
import org.ehcache.impl.config.loaderwriter.writebehind.WriteBehindProviderConfiguration;
import org.ehcache.impl.config.persistence.CacheManagerPersistenceConfiguration;
import org.ehcache.impl.config.serializer.DefaultSerializationProviderConfiguration;
import org.ehcache.impl.config.serializer.DefaultSerializerConfiguration;
import org.ehcache.impl.config.store.heap.DefaultSizeOfEngineConfiguration;
import org.ehcache.impl.config.store.heap.DefaultSizeOfEngineProviderConfiguration;
import org.ehcache.impl.config.store.disk.OffHeapDiskStoreConfiguration;
import org.ehcache.impl.config.store.disk.OffHeapDiskStoreProviderConfiguration;
import org.ehcache.spi.copy.Copier;
import org.ehcache.spi.loaderwriter.CacheLoaderWriter;
import org.ehcache.spi.serialization.Serializer;
import org.ehcache.spi.service.ServiceConfiguration;
import org.ehcache.spi.service.ServiceCreationConfiguration;
import org.ehcache.xml.ConfigurationParser.Batching;
import org.ehcache.xml.ConfigurationParser.WriteBehind;
import org.ehcache.xml.exceptions.XmlConfigurationException;
import org.ehcache.xml.model.CopierType;
import org.ehcache.xml.model.EventType;
import org.ehcache.xml.model.SerializerType;
import org.ehcache.xml.model.ServiceType;
import org.ehcache.xml.model.ThreadPoolReferenceType;
import org.ehcache.xml.model.ThreadPoolsType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

import javax.xml.bind.JAXBException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.ehcache.config.builders.CacheConfigurationBuilder.newCacheConfigurationBuilder;
import static org.ehcache.config.builders.ResourcePoolsBuilder.newResourcePoolsBuilder;

/**
 * Exposes {@link org.ehcache.config.Configuration} and {@link CacheConfigurationBuilder} expressed
 * in a XML file that obeys the core Ehcache schema.
 *

 * Instances of this class are not thread-safe.
 */
public class XmlConfiguration implements Configuration {

  private static final Logger LOGGER = LoggerFactory.getLogger(XmlConfiguration.class);

  private final URL xml;
  private final ClassLoader classLoader;
  private final Map<String, ClassLoader> cacheClassLoaders;

  private final Collection<ServiceCreationConfiguration<?>> serviceConfigurations = new ArrayList<ServiceCreationConfiguration<?>>();
  private final Map<String, CacheConfiguration<?, ?>> cacheConfigurations = new HashMap<String, CacheConfiguration<?, ?>>();
  private final Map<String, ConfigurationParser.CacheTemplate> templates = new HashMap<String, ConfigurationParser.CacheTemplate>();

  /**
   * Constructs an instance of XmlConfiguration mapping to the XML file located at {@code url}
   *

   * Parses the XML file at the {@code url} provided.
   *
   * @param url URL pointing to the XML file's location
   *
   * @throws XmlConfigurationException if anything went wrong parsing the XML
   */
  public XmlConfiguration(URL url)
      throws XmlConfigurationException {
    this(url, ClassLoading.getDefaultClassLoader());
  }

  /**
   * Constructs an instance of XmlConfiguration mapping to the XML file located at {@code url} and using the provided
   * {@code classLoader} to load user types (e.g. key and value Class instances).
   *

   * Parses the XML file at the {@code url} provided.
   *
   * @param url URL pointing to the XML file's location
   * @param classLoader ClassLoader to use to load user types.
   *
   * @throws XmlConfigurationException if anything went wrong parsing the XML
   */
  public XmlConfiguration(URL url, final ClassLoader classLoader)
      throws XmlConfigurationException {
    this(url, classLoader, Collections.<String, ClassLoader>emptyMap());
  }

  /**
   * Constructs an instance of XmlConfiguration mapping to the XML file located at {@code url} and using the provided
   * {@code classLoader} to load user types (e.g. key and value Class instances). The {@code cacheClassLoaders} will
   * let you specify a different {@link java.lang.ClassLoader} to use for each {@link org.ehcache.Cache} managed by
   * the {@link org.ehcache.CacheManager} configured using this {@link org.ehcache.xml.XmlConfiguration}
   *

   * Parses the XML file at the {@code url} provided.
   *
   * @param url URL pointing to the XML file's location
   * @param classLoader ClassLoader to use to load user types.
   * @param cacheClassLoaders the map with mappings between cache names and the corresponding class loaders
   *
   * @throws XmlConfigurationException if anything went wrong parsing the XML
   */
  public XmlConfiguration(URL url, final ClassLoader classLoader, final Map<String, ClassLoader> cacheClassLoaders)
      throws XmlConfigurationException {
    if(url == null) {
      throw new NullPointerException("The url can not be null");
    }
    if(classLoader == null) {
      throw new NullPointerException("The classLoader can not be null");
    }
    if(cacheClassLoaders == null) {
      throw new NullPointerException("The cacheClassLoaders map can not be null");
    }
    this.xml = url;
    this.classLoader = classLoader;
    this.cacheClassLoaders = new HashMap<String, ClassLoader>(cacheClassLoaders);
    try {
      parseConfiguration();
    } catch (XmlConfigurationException e) {
      throw e;
    } catch (Exception e) {
      throw new XmlConfigurationException("Error parsing XML configuration at " + url, e);
    }
  }

  @SuppressWarnings({ "rawtypes", "unchecked" })
  private void parseConfiguration()
      throws ClassNotFoundException, IOException, SAXException, InstantiationException, IllegalAccessException, JAXBException, ParserConfigurationException {
    LOGGER.info("Loading Ehcache XML configuration from {}.", xml.getPath());
    ConfigurationParser configurationParser = new ConfigurationParser(xml.toExternalForm());

    final ArrayList<ServiceCreationConfiguration<?>> serviceConfigs = new ArrayList<ServiceCreationConfiguration<?>>();

    for (ServiceType serviceType : configurationParser.getServiceElements()) {
      final ServiceCreationConfiguration<?> serviceConfiguration = configurationParser.parseExtension(serviceType.getServiceCreationConfiguration());
        serviceConfigs.add(serviceConfiguration);
    }

    if (configurationParser.getDefaultSerializers() != null) {
      DefaultSerializationProviderConfiguration configuration = new DefaultSerializationProviderConfiguration();

      for (SerializerType.Serializer serializer : configurationParser.getDefaultSerializers().getSerializer()) {
        configuration.addSerializerFor(getClassForName(serializer.getType(), classLoader), (Class) getClassForName(serializer.getValue(), classLoader));
      }
      serviceConfigs.add(configuration);
    }
    if (configurationParser.getDefaultCopiers() != null) {
      DefaultCopyProviderConfiguration configuration = new DefaultCopyProviderConfiguration();

      for (CopierType.Copier copier : configurationParser.getDefaultCopiers().getCopier()) {
        configuration.addCopierFor(getClassForName(copier.getType(), classLoader), (Class)getClassForName(copier.getValue(), classLoader));
      }
      serviceConfigs.add(configuration);
    }
    if (configurationParser.getHeapStore() != null) {
      DefaultSizeOfEngineProviderConfiguration configuration = new DefaultSizeOfEngineProviderConfiguration(
              configurationParser.getHeapStore().getMaxObjectSize(), configurationParser.getHeapStore().getUnit(),
              configurationParser.getHeapStore().getMaxObjectGraphSize());
      serviceConfigs.add(configuration);
    }
    if (configurationParser.getPersistence() != null) {
      serviceConfigs.add(new CacheManagerPersistenceConfiguration(new File(configurationParser.getPersistence().getDirectory())));
    }
    if (configurationParser.getThreadPools() != null) {
      PooledExecutionServiceConfiguration poolsConfiguration = new PooledExecutionServiceConfiguration();
      for (ThreadPoolsType.ThreadPool pool : configurationParser.getThreadPools().getThreadPool()) {
        if (pool.isDefault()) {
          poolsConfiguration.addDefaultPool(pool.getAlias(), pool.getMinSize().intValue(), pool.getMaxSize().intValue());
        } else {
          poolsConfiguration.addPool(pool.getAlias(), pool.getMinSize().intValue(), pool.getMaxSize().intValue());
        }
      }
      serviceConfigs.add(poolsConfiguration);
    }
    if (configurationParser.getEventDispatch() != null) {
      ThreadPoolReferenceType eventDispatchThreading = configurationParser.getEventDispatch();
      serviceConfigs.add(new CacheEventDispatcherFactoryConfiguration(eventDispatchThreading.getThreadPool()));
    }
    if (configurationParser.getWriteBehind() != null) {
      ThreadPoolReferenceType writeBehindThreading = configurationParser.getWriteBehind();
      serviceConfigs.add(new WriteBehindProviderConfiguration(writeBehindThreading.getThreadPool()));
    }
    if (configurationParser.getDiskStore() != null) {
      ThreadPoolReferenceType diskStoreThreading = configurationParser.getDiskStore();
      serviceConfigs.add(new OffHeapDiskStoreProviderConfiguration(diskStoreThreading.getThreadPool()));
    }

    for (ServiceCreationConfiguration<?> serviceConfiguration : Collections.unmodifiableList(serviceConfigs)) {
      serviceConfigurations.add(serviceConfiguration);
    }

    for (ConfigurationParser.CacheDefinition cacheDefinition : configurationParser.getCacheElements()) {
      String alias = cacheDefinition.id();

      ClassLoader cacheClassLoader = cacheClassLoaders.get(alias);
      boolean classLoaderConfigured = false;
      if (cacheClassLoader != null) {
        classLoaderConfigured = true;
      }

      if (cacheClassLoader == null) {
        if (classLoader != null) {
          cacheClassLoader = classLoader;
        } else {
          cacheClassLoader = ClassLoading.getDefaultClassLoader();
        }
      }

      Class keyType = getClassForName(cacheDefinition.keyType(), cacheClassLoader);
      Class valueType = getClassForName(cacheDefinition.valueType(), cacheClassLoader);
      ResourcePoolsBuilder resourcePoolsBuilder = newResourcePoolsBuilder();
      for (ResourcePool resourcePool : cacheDefinition.resourcePools()) {
        resourcePoolsBuilder = resourcePoolsBuilder.with(resourcePool);
      }
      CacheConfigurationBuilder<Object, Object> builder = newCacheConfigurationBuilder(keyType, valueType, resourcePoolsBuilder);
      if (classLoaderConfigured) {
        builder = builder.withClassLoader(cacheClassLoader);
      }

      if (cacheDefinition.keySerializer() != null) {
        Class keySerializer = getClassForName(cacheDefinition.keySerializer(), cacheClassLoader);
        builder = builder.add(new DefaultSerializerConfiguration(keySerializer, DefaultSerializerConfiguration.Type.KEY));
      }
      if (cacheDefinition.keyCopier() != null) {
        Class keyCopier = getClassForName(cacheDefinition.keyCopier(), cacheClassLoader);
        builder = builder.add(new DefaultCopierConfiguration(keyCopier, DefaultCopierConfiguration.Type.KEY));
      }
      if (cacheDefinition.valueSerializer() != null) {
        Class valueSerializer = getClassForName(cacheDefinition.valueSerializer(), cacheClassLoader);
        builder = builder.add(new DefaultSerializerConfiguration(valueSerializer, DefaultSerializerConfiguration.Type.VALUE));
      }
      if (cacheDefinition.valueCopier() != null) {
        Class valueCopier = getClassForName(cacheDefinition.valueCopier(), cacheClassLoader);
        builder = builder.add(new DefaultCopierConfiguration(valueCopier, DefaultCopierConfiguration.Type.VALUE));
      }
      if (cacheDefinition.heapStoreSettings() != null) {
        builder = builder.add(new DefaultSizeOfEngineConfiguration(cacheDefinition.heapStoreSettings().getMaxObjectSize(), cacheDefinition.heapStoreSettings().getUnit(),
            cacheDefinition.heapStoreSettings().getMaxObjectGraphSize()));
      }
      EvictionAdvisor evictionAdvisor = getInstanceOfName(cacheDefinition.evictionAdvisor(), cacheClassLoader, EvictionAdvisor.class);
      builder = builder.withEvictionAdvisor(evictionAdvisor);
      final ConfigurationParser.Expiry parsedExpiry = cacheDefinition.expiry();
      if (parsedExpiry != null) {
        builder = builder.withExpiry(getExpiry(cacheClassLoader, parsedExpiry));
      }
      final ConfigurationParser.DiskStoreSettings parsedDiskStoreSettings = cacheDefinition.diskStoreSettings();
      if (parsedDiskStoreSettings != null) {
        builder = builder.add(new OffHeapDiskStoreConfiguration(parsedDiskStoreSettings.threadPool(), parsedDiskStoreSettings.writerConcurrency()));
      }
      for (ServiceConfiguration<?> serviceConfig : cacheDefinition.serviceConfigs()) {
        builder = builder.add(serviceConfig);
      }
      if(cacheDefinition.loaderWriter()!= null) {
        final Class<CacheLoaderWriter<?, ?>> cacheLoaderWriterClass = (Class<CacheLoaderWriter<?,?>>)getClassForName(cacheDefinition.loaderWriter(), cacheClassLoader);
        builder = builder.add(new DefaultCacheLoaderWriterConfiguration(cacheLoaderWriterClass));
        if(cacheDefinition.writeBehind() != null) {
          WriteBehind writeBehind = cacheDefinition.writeBehind();
          WriteBehindConfigurationBuilder writeBehindConfigurationBuilder;
          if (writeBehind.batching() == null) {
            writeBehindConfigurationBuilder = WriteBehindConfigurationBuilder.newUnBatchedWriteBehindConfiguration();
          } else {
            Batching batching = writeBehind.batching();
            writeBehindConfigurationBuilder = WriteBehindConfigurationBuilder
                    .newBatchedWriteBehindConfiguration(batching.maxDelay(), batching.maxDelayUnit(), batching.batchSize());
            if (batching.isCoalesced()) {
              writeBehindConfigurationBuilder = ((BatchedWriteBehindConfigurationBuilder) writeBehindConfigurationBuilder).enableCoalescing();
            }
          }
          builder = builder.add(writeBehindConfigurationBuilder
                  .useThreadPool(writeBehind.threadPool())
                  .concurrencyLevel(writeBehind.concurrency())
                  .queueSize(writeBehind.maxQueueSize()));
        }
      }
      builder = handleListenersConfig(cacheDefinition.listenersConfig(), cacheClassLoader, builder);
      final CacheConfiguration<?, ?> config = builder.build();
      cacheConfigurations.put(alias, config);
    }

    templates.putAll(configurationParser.getTemplates());
  }

  private Expiry<? super Object, ? super Object> getExpiry(ClassLoader cacheClassLoader, ConfigurationParser.Expiry parsedExpiry)
      throws ClassNotFoundException, InstantiationException, IllegalAccessException {
    final Expiry<? super Object, ? super Object> expiry;
    if (parsedExpiry.isUserDef()) {
      expiry = getInstanceOfName(parsedExpiry.type(), cacheClassLoader, Expiry.class);
    } else if (parsedExpiry.isTTL()) {
      expiry = Expirations.timeToLiveExpiration(new Duration(parsedExpiry.value(), parsedExpiry.unit()));
    } else if (parsedExpiry.isTTI()) {
      expiry = Expirations.timeToIdleExpiration(new Duration(parsedExpiry.value(), parsedExpiry.unit()));
    } else {
      expiry = Expirations.noExpiration();
    }
    return expiry;
  }

  private static <T> T getInstanceOfName(String name, ClassLoader classLoader, Class<T> type) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
    if (name == null) {
      return null;
    }
    Class<?> klazz = getClassForName(name, classLoader);
    return klazz.asSubclass(type).newInstance();
  }

  private static Class<?> getClassForName(String name, ClassLoader classLoader) throws ClassNotFoundException {
    return Class.forName(name, true, classLoader);
  }

  /**
   * Exposes the URL where the XML file parsed or yet to be parsed was or will be sourced from.
   * @return The URL provided at object instantiation
   */
  public URL getURL() {
    return xml;
  }

  /**
   * Creates a new {@link CacheConfigurationBuilder} seeded with the cache-template configuration
   * by the given {@code name} in the XML configuration parsed using {@link #parseConfiguration()}.
   *

   *   Note that this version does not specify resources, which are mandatory to create a
   *   {@link CacheConfigurationBuilder}. So if the template does not define resources, this will throw.
   *

   *
   * @param name the unique name identifying the cache-template element in the XML
   * @param keyType the type of keys for the {@link CacheConfigurationBuilder} to use, must
   *                match the {@code key-type} declared in the template if declared in XML
   * @param valueType the type of values for the {@link CacheConfigurationBuilder} to use, must
   *                  match the {@code value-type} declared in the template if declared in XML
   * @param <K> type of keys
   * @param <V> type of values
   *
   * @return the preconfigured {@link CacheConfigurationBuilder}
   *         or {@code null} if no cache-template for the provided {@code name}
   *
   * @throws IllegalStateException if {@link #parseConfiguration()} hasn't yet been successfully invoked or the template
   * does not configure resources.
   * @throws IllegalArgumentException if {@code keyType} or {@code valueType} don't match the declared type(s) of the template
   * @throws ClassNotFoundException if a {@link java.lang.Class} declared in the XML couldn't be found
   * @throws InstantiationException if a user provided {@link java.lang.Class} couldn't get instantiated
   * @throws IllegalAccessException if a method (including constructor) couldn't be invoked on a user provided type
   */
  @SuppressWarnings("unchecked")
  public <K, V> CacheConfigurationBuilder<K, V> newCacheConfigurationBuilderFromTemplate(final String name,
                                                                                final Class<K> keyType,
                                                                                final Class<V> valueType)
      throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    return internalCacheConfigurationBuilderFromTemplate(name, keyType, valueType, null);
  }

  /**
   * Creates a new {@link CacheConfigurationBuilder} seeded with the cache-template configuration
   * by the given {@code name} in the XML configuration parsed using {@link #parseConfiguration()}.
   *
   * @param name the unique name identifying the cache-template element in the XML
   * @param keyType the type of keys for the {@link CacheConfigurationBuilder} to use, must
   *                match the {@code key-type} declared in the template if declared in XML
   * @param valueType the type of values for the {@link CacheConfigurationBuilder} to use, must
   *                  match the {@code value-type} declared in the template if declared in XML
   * @param resourcePools Resources definitions that will be used
   * @param <K> type of keys
   * @param <V> type of values
   *
   * @return the preconfigured {@link CacheConfigurationBuilder}
   *         or {@code null} if no cache-template for the provided {@code name}
   *
   * @throws IllegalStateException if {@link #parseConfiguration()} hasn't yet been successfully invoked
   * @throws IllegalArgumentException if {@code keyType} or {@code valueType} don't match the declared type(s) of the template
   * @throws ClassNotFoundException if a {@link java.lang.Class} declared in the XML couldn't be found
   * @throws InstantiationException if a user provided {@link java.lang.Class} couldn't get instantiated
   * @throws IllegalAccessException if a method (including constructor) couldn't be invoked on a user provided type
   */
  @SuppressWarnings("unchecked")
  public <K, V> CacheConfigurationBuilder<K, V> newCacheConfigurationBuilderFromTemplate(final String name,
                                                                                final Class<K> keyType,
                                                                                final Class<V> valueType,
                                                                                final ResourcePools resourcePools)
      throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    if (resourcePools == null || resourcePools.getResourceTypeSet().isEmpty()) {
      throw new IllegalArgumentException("ResourcePools parameter must define at least one resource");
    }
    return internalCacheConfigurationBuilderFromTemplate(name, keyType, valueType, resourcePools);
  }

  /**
   * Creates a new {@link CacheConfigurationBuilder} seeded with the cache-template configuration
   * by the given {@code name} in the XML configuration parsed using {@link #parseConfiguration()}.
   *
   * @param name the unique name identifying the cache-template element in the XML
   * @param keyType the type of keys for the {@link CacheConfigurationBuilder} to use, must
   *                match the {@code key-type} declared in the template if declared in XML
   * @param valueType the type of values for the {@link CacheConfigurationBuilder} to use, must
   *                  match the {@code value-type} declared in the template if declared in XML
   * @param resourcePoolsBuilder Resources definitions that will be used
   * @param <K> type of keys
   * @param <V> type of values
   *
   * @return the preconfigured {@link CacheConfigurationBuilder}
   *         or {@code null} if no cache-template for the provided {@code name}
   *
   * @throws IllegalStateException if {@link #parseConfiguration()} hasn't yet been successfully invoked
   * @throws IllegalArgumentException if {@code keyType} or {@code valueType} don't match the declared type(s) of the template
   * @throws ClassNotFoundException if a {@link java.lang.Class} declared in the XML couldn't be found
   * @throws InstantiationException if a user provided {@link java.lang.Class} couldn't get instantiated
   * @throws IllegalAccessException if a method (including constructor) couldn't be invoked on a user provided type
   */
  @SuppressWarnings("unchecked")
  public <K, V> CacheConfigurationBuilder<K, V> newCacheConfigurationBuilderFromTemplate(final String name,
                                                                                final Class<K> keyType,
                                                                                final Class<V> valueType,
                                                                                final Builder<? extends ResourcePools> resourcePoolsBuilder)
      throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    return internalCacheConfigurationBuilderFromTemplate(name, keyType, valueType, resourcePoolsBuilder.build());
  }

  private <K, V> CacheConfigurationBuilder<K, V> internalCacheConfigurationBuilderFromTemplate(final String name,
                                                                                final Class<K> keyType,
                                                                                final Class<V> valueType,
                                                                                final ResourcePools resourcePools)
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {

    final ConfigurationParser.CacheTemplate cacheTemplate = templates.get(name);
    if (cacheTemplate == null) {
      return null;
    }
    final ClassLoader defaultClassLoader = ClassLoading.getDefaultClassLoader();
    Class keyClass = getClassForName(cacheTemplate.keyType(), defaultClassLoader);
    Class valueClass = getClassForName(cacheTemplate.valueType(), defaultClassLoader);
    if(keyType != null && cacheTemplate.keyType() != null && !keyClass.isAssignableFrom(keyType)) {
      throw new IllegalArgumentException("CacheTemplate '" + name + "' declares key type of " + cacheTemplate.keyType());
    }
    if(valueType != null && cacheTemplate.valueType() != null && !valueClass.isAssignableFrom(valueType)) {
      throw new IllegalArgumentException("CacheTemplate '" + name + "' declares value type of " + cacheTemplate.valueType());
    }

    if ((resourcePools == null || resourcePools.getResourceTypeSet().isEmpty()) && cacheTemplate.resourcePools().isEmpty()) {
      throw new IllegalStateException("Template defines no resources, and none were provided");
    }
    CacheConfigurationBuilder<K, V> builder;
    if (resourcePools != null) {
      builder = newCacheConfigurationBuilder(keyType, valueType, resourcePools);
    } else {
      ResourcePoolsBuilder resourcePoolsBuilder = newResourcePoolsBuilder();
      for (ResourcePool resourcePool : cacheTemplate.resourcePools()) {
        resourcePoolsBuilder = resourcePoolsBuilder.with(resourcePool);
      }
      builder = newCacheConfigurationBuilder(keyType, valueType, resourcePoolsBuilder);
    }
    builder = builder
        .withEvictionAdvisor(getInstanceOfName(cacheTemplate.evictionAdvisor(), defaultClassLoader, EvictionAdvisor.class));
    final ConfigurationParser.Expiry parsedExpiry = cacheTemplate.expiry();
    if (parsedExpiry != null) {
      builder = builder.withExpiry(getExpiry(defaultClassLoader, parsedExpiry));
    }

    if (cacheTemplate.keySerializer() != null) {
      final Class<Serializer<?>> keySerializer = (Class<Serializer<?>>) getClassForName(cacheTemplate.keySerializer(), defaultClassLoader);
      builder = builder.add(new DefaultSerializerConfiguration(keySerializer, DefaultSerializerConfiguration.Type.KEY));
    }
    if (cacheTemplate.keyCopier() != null) {
      final Class<Copier<?>> keyCopier = (Class<Copier<?>>) getClassForName(cacheTemplate.keyCopier(), defaultClassLoader);
      builder = builder.add(new DefaultCopierConfiguration(keyCopier, DefaultCopierConfiguration.Type.KEY));
    }
    if (cacheTemplate.valueSerializer() != null) {
      final Class<Serializer<?>> valueSerializer = (Class<Serializer<?>>) getClassForName(cacheTemplate.valueSerializer(), defaultClassLoader);
      builder = builder.add(new DefaultSerializerConfiguration(valueSerializer, DefaultSerializerConfiguration.Type.VALUE));
    }
    if (cacheTemplate.valueCopier() != null) {
      final Class<Copier<?>> valueCopier = (Class<Copier<?>>) getClassForName(cacheTemplate.valueCopier(), defaultClassLoader);
      builder = builder.add(new DefaultCopierConfiguration(valueCopier, DefaultCopierConfiguration.Type.VALUE));
    }
    if (cacheTemplate.heapStoreSettings() != null) {
      builder = builder.add(new DefaultSizeOfEngineConfiguration(cacheTemplate.heapStoreSettings().getMaxObjectSize(), cacheTemplate.heapStoreSettings().getUnit(),
        cacheTemplate.heapStoreSettings().getMaxObjectGraphSize()));
    }
    final String loaderWriter = cacheTemplate.loaderWriter();
    if(loaderWriter!= null) {
      final Class<CacheLoaderWriter<?, ?>> cacheLoaderWriterClass = (Class<CacheLoaderWriter<?,?>>)getClassForName(loaderWriter, defaultClassLoader);
      builder = builder.add(new DefaultCacheLoaderWriterConfiguration(cacheLoaderWriterClass));
      if(cacheTemplate.writeBehind() != null) {
        WriteBehind writeBehind = cacheTemplate.writeBehind();
        WriteBehindConfigurationBuilder writeBehindConfigurationBuilder;
        if (writeBehind.batching() == null) {
          writeBehindConfigurationBuilder = WriteBehindConfigurationBuilder.newUnBatchedWriteBehindConfiguration();
        } else {
          Batching batching = writeBehind.batching();
          writeBehindConfigurationBuilder = WriteBehindConfigurationBuilder.newBatchedWriteBehindConfiguration(batching.maxDelay(), batching.maxDelayUnit(), batching.batchSize());
          if (batching.isCoalesced()) {
            writeBehindConfigurationBuilder = ((BatchedWriteBehindConfigurationBuilder) writeBehindConfigurationBuilder).enableCoalescing();
          }
        }
        builder = builder.add(writeBehindConfigurationBuilder
                .concurrencyLevel(writeBehind.concurrency())
                .queueSize(writeBehind.maxQueueSize()));
      }
    }
    builder = handleListenersConfig(cacheTemplate.listenersConfig(), defaultClassLoader, builder);
    for (ServiceConfiguration<?> serviceConfiguration : cacheTemplate.serviceConfigs()) {
      builder = builder.add(serviceConfiguration);
    }
    return builder;
  }

  private <K, V> CacheConfigurationBuilder<K, V> handleListenersConfig(ConfigurationParser.ListenersConfig listenersConfig, ClassLoader defaultClassLoader, CacheConfigurationBuilder<K, V> builder) throws ClassNotFoundException {
    if(listenersConfig != null) {
      if (listenersConfig.threadPool() != null) {
        builder = builder.add(new DefaultCacheEventDispatcherConfiguration(listenersConfig.threadPool()));
      }
      if (listenersConfig.listeners() != null) {
        for (ConfigurationParser.Listener listener : listenersConfig.listeners()) {
          final Class<CacheEventListener<?, ?>> cacheEventListenerClass = (Class<CacheEventListener<?, ?>>)getClassForName(listener.className(), defaultClassLoader);
          final List<EventType> eventListToFireOn = listener.fireOn();
          Set<org.ehcache.event.EventType> eventSetToFireOn = new HashSet<org.ehcache.event.EventType>();
          for (EventType events : eventListToFireOn) {
            switch (events) {
              case CREATED:
                eventSetToFireOn.add(org.ehcache.event.EventType.CREATED);
                break;
              case EVICTED:
                eventSetToFireOn.add(org.ehcache.event.EventType.EVICTED);
                break;
              case EXPIRED:
                eventSetToFireOn.add(org.ehcache.event.EventType.EXPIRED);
                break;
              case UPDATED:
                eventSetToFireOn.add(org.ehcache.event.EventType.UPDATED);
                break;
              case REMOVED:
                eventSetToFireOn.add(org.ehcache.event.EventType.REMOVED);
                break;
              default:
                throw new IllegalArgumentException("Invalid Event Type provided");
            }
          }
          CacheEventListenerConfigurationBuilder listenerBuilder = CacheEventListenerConfigurationBuilder
              .newEventListenerConfiguration(cacheEventListenerClass, eventSetToFireOn)
              .firingMode(EventFiring.valueOf(listener.eventFiring().value()))
              .eventOrdering(EventOrdering.valueOf(listener.eventOrdering().value()));
          builder = builder.add(listenerBuilder);
        }
      }
    }
    return builder;
  }

  @Override
  public Map<String, CacheConfiguration<?, ?>> getCacheConfigurations() {
    return cacheConfigurations;
  }

  @Override
  public Collection<ServiceCreationConfiguration<?>> getServiceCreationConfigurations() {
    return serviceConfigurations;
  }

  @Override
  public ClassLoader getClassLoader() {
    return classLoader;
  }
}


text:
define([
  'aeris/util',
  'aeris/subsetcollection',
  'aeris/model',
  'aeris/collection',
  'aeris/promise'
], function(_, SubsetCollection, Model, Collection, Promise) {
  var Types = {
    TYPE_A: 'TYPE_A',
    TYPE_B: 'TYPE_B',
    TYPE_C: 'TYPE_C'
  };

  var BulkModels = function(opt_modelCount, opt_ModelType) {
    this.modelCount_ = opt_modelCount || 5;
    this.ModelType_ = opt_ModelType || Model;
    this.models_ = this.createModels_();

    return this.models_;
  };

  BulkModels.prototype.createModels_ = function() {
    var models = [];

    _.times(this.modelCount_, function(i) {
      var model = new this.ModelType_();

      model.jasmineToString = function() {
        return model.cid || i;
      };

      models.push(model);
    }, this);

    return models;
  };

  /**
   * Creates models with a 'type' attribute.
   *
   * @param {string} type
   * @return {Model}
   * @constructor
   */
  var ModelTypeFactory = function(type) {
    var model = new Model({ type: type });

    model.jasmineToString = function() {
      return 'MODEL_' + type;
    };

    return model;
  };

  var ModelTypeA = _.partial(ModelTypeFactory, Types.TYPE_A);
  var ModelTypeB = _.partial(ModelTypeFactory, Types.TYPE_B);
  var ModelTypeC = _.partial(ModelTypeFactory, Types.TYPE_C);

  var isType = function(type, model) {
    return model.get('type') === type;
  };

  var isTypeA = _.partial(isType, Types.TYPE_A);
  var isTypeB = _.partial(isType, Types.TYPE_B);
  var isTypeC = _.partial(isType, Types.TYPE_C);

  function isMaintainingLimit(subsetCollection, limit) {
    var sourceCollection = subsetCollection.getSourceCollection();

    if (sourceCollection.length >= limit) {
      return subsetCollection.length === limit;
    }
    // Source is under limit,
    // so our subset should be the same length as the source
    else {
      return subsetCollection.length === sourceCollection.length;
    }
  }

  describe('SubsetCollection', function() {
    var subsetCollection, sourceCollection;
    var modelTypeA, modelTypeB, modelTypeC, modelTypesABC;

    beforeEach(function() {
      sourceCollection = new Collection();
      subsetCollection = new SubsetCollection(sourceCollection);
    });

    beforeEach(function() {
      modelTypeA = new ModelTypeA();
      modelTypeB = new ModelTypeB();
      modelTypeC = new ModelTypeC();

      modelTypesABC = [modelTypeA, modelTypeB, modelTypeC];
    });

    beforeEach(function() {
      this.addMatchers({
        toOnlyContainSourceModels: function() {
          var subsetCollection = this.actual;
          var sourceCollection = subsetCollection.getSourceCollection();

          var differentModels = _.difference(subsetCollection.models, sourceCollection.models);

          this.message = !this.isNot ?
            function() {
              return 'Expected subset to contain only models in the source, ' +
                'but it also contained: ' + jasmine.pp(differentModels);
            } :
            function() {
              return 'Expected subset not to contain only models in the source';
            };

          return differentModels.length === 0;
        },
        toMatchTheSourceOrder: function() {
          var subsetCollection = this.actual;
          var sourceCollection = subsetCollection.getSourceCollection();

          var isCorrectOrder = subsetCollection.reduce(function(isCorrect, subsetModel) {
            var nextSubsetModel, prevSubsetModel, subsetModelIndex;
            var isNextInCorrectPosition = true, isPrevInCorrectPosition = true;

            if (!sourceCollection.contains(subsetModel)) {
              return isCorrect;
            }

            subsetModelIndex = subsetCollection.indexOf(subsetModel);
            nextSubsetModel = subsetCollection.at(subsetModelIndex + 1);
            prevSubsetModel = subsetCollection.at(subsetModelIndex - 1);

            if (sourceCollection.contains(nextSubsetModel)) {
              isNextInCorrectPosition = sourceCollection.indexOf(nextSubsetModel) > sourceCollection.indexOf(subsetModel);
            }
            if (sourceCollection.contains(prevSubsetModel)) {
              isPrevInCorrectPosition = sourceCollection.indexOf(prevSubsetModel) < sourceCollection.indexOf(subsetModel);
            }

            return isNextInCorrectPosition && isPrevInCorrectPosition ? isCorrect : false;
          }, true);

          this.message = !this.isNot ?
            function() {
              return 'Expected subset models to be in the same order as the source models';
            } :
            function() {
              return 'Expected subset models not ot be in the same order as the source models';
            };

          return isCorrectOrder;
        },
        toEnforceFilterAndLimit: function(filter, limit) {
          var subsetCollection = this.actual;
          var sourceCollection = subsetCollection.getSourceCollection();
          var filteredSourceModels, filteredAndLimitedSourceModels;

          !_.isNull(limit) || (limit = sourceCollection.length);
          filter || (filter = _.constant(true));

          filteredSourceModels = sourceCollection.filter(filter);
          filteredAndLimitedSourceModels = filteredSourceModels.slice(0, limit);

          this.message = !this.isNot ?
            function() {
              return 'Expected subset collection to enforce a filter and limit, ' +
                'with models ' + jasmine.pp(filteredAndLimitedSourceModels) + ', ' +
                'but actual subset models are ' + jasmine.pp(subsetCollection.models);
            } :
            function() {
              return 'Expected subset collection not to enforce filter and limit. Subset colleciton ' +
                'models: ' + jasmine.pp(subsetCollection.models);
            };

          return _.isEqual(subsetCollection.models, filteredAndLimitedSourceModels);
        }
      });
    });

    describe('speed test', function() {
      var BigModel = function() {
        return new Model({
          data: {
            that: {
              is: {
                nested: {
                  really: 'deep'
                }
              }
            }
          },
          and: [
            'there',
            'are',
            'some',
            'arrays',
            { of: 'data' }
          ].map(function(arr) {
              return { even: { deeper: arr }};
            })
        });
      };

      // Shim performance.now (not supported by PhantomJS)
      if (!window.performance || !window.performance.now) {
        window.performance = _.extend({}, window.performance, {
          now: function() {
            return Date.now();
          }
        });
      }

      function speedTest(count, iterations) {
        var times = [], totalTime, averageTime;

        _.times(iterations, function() {
          var lotsOfModels = new BulkModels(count, BigModel);
          var startTime = performance.now();

          // Add a bunch of models
          _.each(lotsOfModels, function(model) {
            sourceCollection.add(model);
          });

          // Remove a bunch of models
          _.each(lotsOfModels.slice(0, count / 2), function(model) {
            sourceCollection.remove(model);
          });

          // Record how much time it tooke
          times.push(performance.now() - startTime);
        });

        totalTime = times.reduce(function(sum, current) {
          return sum + current;
        }, 0);
        averageTime = totalTime / times.length;

        return averageTime;
      }

      it('adding and removing models', function() {
        expect(speedTest(200, 20)).toBeLessThan(200);
      });

      it('adding and removing models, with limit', function() {
        subsetCollection.setLimit(200);
        expect(speedTest(200, 20)).toBeLessThan(200);
      });

      it('adding and removing models, with filter', function() {
        subsetCollection.setFilter(function() {
          return Math.random() > 0.5;
        });
        expect(speedTest(200, 20)).toBeLessThan(200);
      });

      it('adding and removing models, with limit and filter', function() {
        subsetCollection.setLimit(200);
        subsetCollection.setFilter(function() {
          return Math.random() > 0.5;
        });
        expect(speedTest(200, 20)).toBeLessThan(200);
      });

    });

    describe('constructor', function() {

      it('should reject invalid source collections', function() {

        expect(function() {
          new SubsetCollection();
        }).toThrowType('InvalidArgumentError');

        expect(function() {
          new SubsetCollection('foo');
        }).toThrowType('InvalidArgumentError');

      });

      it('should accept a collection as a source', function() {
        new SubsetCollection(sourceCollection);
      });

      it('should should accept an array of models as a source', function() {
        new SubsetCollection([new Model(), new Model()]);
      });

      it('should add source collection\'s models (without filter or limit)', function() {
        sourceCollection.add(modelTypesABC);

        subsetCollection = new SubsetCollection(sourceCollection);

        expect(subsetCollection.models).toEqual(modelTypesABC);
      });

    });

    describe('Data binding to source collection', function() {

      function itShouldStayInSync() {

        it('should stay in sync when models are added to the source collection', function() {
          sourceCollection.add(modelTypesABC);
        });

        it('should stay in sync when models are removed from the source collection', function() {
          sourceCollection.add(modelTypesABC);

          sourceCollection.remove(modelTypeB);
        });

        it('should stay in sync when models are reset from the source collection (no new models)', function() {
          sourceCollection.add(modelTypesABC);

          sourceCollection.reset();
        });

        it('should stay in sync when models are reset from the source collection (with new models)', function() {
          var newModels = new BulkModels(3);
          sourceCollection.add(modelTypesABC);

          sourceCollection.reset(newModels);
        });

        it('should stay in sync when models are changed in the source collection', function() {
          sourceCollection.add(modelTypesABC);

          sourceCollection.at(1).set('type', 'changed type');
        });
      }

      function itShouldStayInSyncWithLimit(limit) {

        it('more models than the limit are added', function() {
          sourceCollection.add(new BulkModels(limit + 5));
        });

        it('fewer models than the limit are added', function() {
          sourceCollection.add(new BulkModels(limit - 2));
        });

        it('models are added at an index above the limit', function() {
          sourceCollection.add(new BulkModels(limit - 5));
          sourceCollection.add(new BulkModels(10));
        });

        it('models are added at an index straddling the limit', function() {
          sourceCollection.add(new BulkModels(limit + 5));
          sourceCollection.add(new BulkModels(5), { at: 8 });
        });

        it('models are added to the source at an index inside the limit', function() {
          sourceCollection.add(new BulkModels(limit + 5));
          sourceCollection.add(new BulkModels(3), { at: 1 });
        });

        it('models are removed from the source at an index inside the limit', function() {
          var models = new BulkModels(limit + 5);
          sourceCollection.add(models);
          sourceCollection.remove(models[1], models[2], models[4]);
        });

        it('models are removed from the source at an index outside the limit', function() {
          var models = new BulkModels(limit + 5);
          sourceCollection.add(models);

          sourceCollection.remove(models[limit + 2], models[limit + 3]);
        });

        it('models are removed from the source at an index straddling the limit', function() {
          var models = new BulkModels(limit + 5);
          sourceCollection.add(models);

          sourceCollection.remove(models[limit - 2], models[limit], models[limit + 2]);
        });

        it('source models are reset, with more models than the limit', function() {
          sourceCollection.add(new BulkModels(limit + 5));

          sourceCollection.reset(new BulkModels(limit + 5));
        });

        it('source models are reset, with fewer models than the limit', function() {
          sourceCollection.add(new BulkModels(limit + 5));

          sourceCollection.reset(new BulkModels(limit - 2));
        });

        it('source models are reset, with no models added', function() {
          sourceCollection.add(new BulkModels(limit + 5));

          sourceCollection.reset();
        });

      }

      afterEach(function() {
        expect(subsetCollection).toOnlyContainSourceModels();
        expect(subsetCollection).toMatchTheSourceOrder();
      });

      describe('without a filter or limit', function() {

        itShouldStayInSync();

        afterEach(function() {
          expect(subsetCollection.length).toEqual(sourceCollection.length);
        });

      });

      describe('when a filter is set (no limit)', function() {

        beforeEach(function() {
          subsetCollection.setFilter(isTypeB);
        });

        itShouldStayInSync();

        afterEach(function() {
          expect(subsetCollection).toEnforceFilterAndLimit(isTypeB, null);
        });

      });

      describe('when a limit is set (no filter)', function() {
        var LIMIT = 10;

        beforeEach(function() {
          subsetCollection.setLimit(LIMIT);
        });

        it('should not fire unecessary events', function() {
          var onAdd = jasmine.createSpy('onAdd');
          var onRemove = jasmine.createSpy('onRemove');
          subsetCollection.on({
            add: onAdd,
            remove: onRemove
          });

          sourceCollection.add(new BulkModels(15));
          expect(onAdd.callCount).toEqual(LIMIT);
          expect(onRemove.callCount).toEqual(0);
        });

        itShouldStayInSync();
        itShouldStayInSyncWithLimit(LIMIT);

        afterEach(function() {
          expect(subsetCollection).toEnforceFilterAndLimit(null, LIMIT);
        });

      });

      describe('when a filter and a limit are set', function() {
        var LIMIT = 10;

        beforeEach(function() {
          subsetCollection.setLimit(LIMIT);
          subsetCollection.setFilter(isTypeB);
        });

        itShouldStayInSync();
        itShouldStayInSyncWithLimit(LIMIT);

        describe('when a source model is changed', function() {

          describe('so that it passes the filter', function() {

            describe('and the model is within the limit', function() {

              it('should be added to the subset', function() {
                var models = new BulkModels(LIMIT + 5);
                var changingModel = models[LIMIT - 2];

                changingModel.set('type', Types.TYPE_A);                          // model fails filter
                sourceCollection.add(models);
                expect(subsetCollection.contains(changingModel)).toEqual(false);  // baseline test

                changingModel.set('type', Types.TYPE_B);                          // model passes filter
                expect(subsetCollection.contains(changingModel)).toEqual(true);
              });

            });

            describe('and the model is outside the limit', function() {

              it('should not be added to the subset', function() {
                var models = new BulkModels(LIMIT + 5, ModelTypeB);
                var changingModel = models[LIMIT + 2];

                changingModel.set('type', Types.TYPE_A);                          // model fails filter
                sourceCollection.add(models);
                expect(subsetCollection.contains(changingModel)).toEqual(false);  // baseline test

                changingModel.set('type', Types.TYPE_B);                          // model passes filter
                expect(subsetCollection.contains(changingModel)).toEqual(false);
              });

            });

          });

          describe('so that it fails the filter', function() {

            describe('and the model is within the limit', function() {

              it('should be removed from the subset', function() {
                var models = new BulkModels(LIMIT + 5);
                var changingModel = models[LIMIT - 2];

                changingModel.set('type', Types.TYPE_B);                          // model passes filter
                sourceCollection.add(models);
                expect(subsetCollection.contains(changingModel)).toEqual(true);  // baseline test

                changingModel.set('type', Types.TYPE_C);                          // model fails filter
                expect(subsetCollection.contains(changingModel)).toEqual(false);
              });

            });

            describe('and the model is outside the limit', function() {

              it('should not be added to the subset', function() {
                var models = new BulkModels(LIMIT + 5, ModelTypeB);
                var changingModel = models[LIMIT + 2];

                sourceCollection.add(models);
                expect(subsetCollection.contains(changingModel)).toEqual(false);  // baseline test

                changingModel.set('type', Types.TYPE_C);                          // model fails filter
                expect(subsetCollection.contains(changingModel)).toEqual(false);
              });

            });

          });

        });

        afterEach(function() {
          expect(subsetCollection.length <= LIMIT).toEqual(true);
          expect(subsetCollection).toEnforceFilterAndLimit(isTypeB, LIMIT);
        });

      });

      it('should not reference the source collection\'s models array', function() {
        sourceCollection.add(modelTypesABC);

        subsetCollection.models.splice(0, 2);

        expect(sourceCollection.models).toEqual(modelTypesABC);
      });

    });

    describe('Events', function() {

      describe('request', function() {
        var onRequest, PROMISE_STUB = 'PROMISE_STUB';

        beforeEach(function() {
          onRequest = jasmine.createSpy('onRequest');
          subsetCollection.on('request', onRequest);
        });

        it('should proxy the source collection\'s \'request\' event ', function() {
          sourceCollection.trigger('request', sourceCollection, PROMISE_STUB);

          expect(onRequest).toHaveBeenCalledWith(sourceCollection, PROMISE_STUB);
        });

      });

      describe('sync', function() {
        var onSync, RESP_STUB = 'RESP_STUB';

        beforeEach(function() {
          onSync = jasmine.createSpy('onSync');
          subsetCollection.on('sync', onSync);
        });

        it('should proxy the source collection\'s \'sync\' event ', function() {
          sourceCollection.trigger('sync', sourceCollection, RESP_STUB);

          expect(onSync).toHaveBeenCalledWith(sourceCollection, RESP_STUB);
        });

      });

      describe('error', function() {
        var onError, RESP_STUB = 'RESP_STUB';

        beforeEach(function() {
          onError = jasmine.createSpy('onError');
          subsetCollection.on('error', onError);
        });

        it('should proxy the source collection\'s \'error\' event ', function() {
          sourceCollection.trigger('error', sourceCollection, RESP_STUB);

          expect(onError).toHaveBeenCalledWith(sourceCollection, RESP_STUB);
        });

      });

    });

    describe('setLimit', function() {
      var LIMIT = 10;

      it('should remove any models beyond the limit', function() {
        sourceCollection.add(new BulkModels(LIMIT + 5));

        subsetCollection.setLimit(LIMIT);
        expect(subsetCollection.length).toEqual(LIMIT);
      });

      it('should not remove models if the subset has fewer models than the limit', function() {
        sourceCollection.add(new BulkModels(LIMIT - 2));

        subsetCollection.setLimit(LIMIT);
        expect(subsetCollection.length).toEqual(LIMIT - 2);
      });

      describe('when the source has more models than the current limit', function() {

        beforeEach(function() {
          subsetCollection.setLimit(LIMIT - 3);
        });

        it('should add models from source', function() {
          sourceCollection.add(new BulkModels(LIMIT + 5));

          subsetCollection.setLimit(LIMIT);
          expect(subsetCollection.length).toEqual(LIMIT);
        });

      });

      it('should not add any models if the source has none available', function() {
        sourceCollection.reset();

        subsetCollection.setLimit(LIMIT);

        expect(subsetCollection.length).toEqual(0);
      });

      afterEach(function() {
        expect(subsetCollection).toEnforceFilterAndLimit(null, LIMIT);
        expect(subsetCollection).toOnlyContainSourceModels();
        expect(subsetCollection).toMatchTheSourceOrder();
      });

    });

    describe('removeLimit', function() {
      var LIMIT = 10;

      beforeEach(function() {
        subsetCollection.setLimit(10);
      });

      it('should add all previously over-limit models from the source', function() {
        sourceCollection.add(new BulkModels(LIMIT + 5));

        subsetCollection.removeLimit();

        expect(subsetCollection.length).toEqual(LIMIT + 5);
      });

      it('should allow models added to the source to be added to the subset (data binding)', function() {
        subsetCollection.removeLimit();

        sourceCollection.add(new BulkModels(LIMIT + 5));

        expect(subsetCollection.length).toEqual(LIMIT + 5);
      });

      afterEach(function() {
        expect(subsetCollection).toOnlyContainSourceModels();
        expect(subsetCollection).toMatchTheSourceOrder();
      });

    });

    describe('setFilter', function() {

      it('should update models from the source collection, using the filter', function() {
        sourceCollection.add(modelTypesABC);

        subsetCollection.setFilter(isTypeA);
        expect(subsetCollection.models).toEqual([modelTypeA]);

        subsetCollection.setFilter(function(model) {
          return isTypeB(model) || isTypeC(model);
        });
        expect(subsetCollection.models).toEqual([modelTypeB, modelTypeC]);
      });

      it('should not compound filters', function() {
        sourceCollection.add([modelTypeA, modelTypeB, modelTypeC]);

        subsetCollection.setFilter(isTypeA);

        // Setting a second filter should start us fresh
        // from sourceCollection models
        // (ie should not be isTypeA && isTypeB)
        subsetCollection.setFilter(isTypeB);

        expect(subsetCollection.models).toEqual([modelTypeB]);
      });

      it('should use the filter when adding new models from the source collection', function() {
        var modelA_2 = new ModelTypeA();
        subsetCollection.setFilter(isTypeA);

        sourceCollection.add([modelTypeA, modelTypeB]);
        expect(subsetCollection.models).toEqual([modelTypeA]);

        sourceCollection.reset([modelTypeA, modelTypeC]);
        expect(subsetCollection.models).toEqual([modelTypeA]);

        sourceCollection.add(modelA_2);
        expect(subsetCollection.models).toEqual([modelTypeA, modelA_2]);
      });

      it('should set the context of the filter', function() {
        var ctx = { STUB: 'CTX' };
        var filter = jasmine.createSpy('filter').andCallFake(function() {
          expect(this).toEqual(ctx);
          return true;
        });

        subsetCollection.setFilter(filter, ctx);
        sourceCollection.add([modelTypeA, modelTypeB]);

        expect(filter).toHaveBeenCalled();
      });

      afterEach(function() {
        expect(subsetCollection).toOnlyContainSourceModels();
        expect(subsetCollection).toMatchTheSourceOrder();
      });

    });

    describe('removeFilter', function() {

      beforeEach(function() {
        subsetCollection.setFilter(isTypeB);

        sourceCollection.add(modelTypesABC);
      });

      it('should add all models from the source collection', function() {
        subsetCollection.removeFilter();
        expect(subsetCollection.contains(modelTypeA)).toEqual(true);
        expect(subsetCollection.contains(modelTypeB)).toEqual(true);
        expect(subsetCollection.contains(modelTypeC)).toEqual(true);
      });

      it('should not use the previous filter when new models are added to the source', function() {
        var newModelTypeB = new ModelTypeB();

        subsetCollection.removeFilter();

        sourceCollection.add(newModelTypeB);

        expect(subsetCollection.contains(newModelTypeB)).toEqual(true);
      });

      afterEach(function() {
        expect(subsetCollection).toOnlyContainSourceModels();
        expect(subsetCollection).toMatchTheSourceOrder();
      });
    });

    describe('fetch', function() {

      beforeEach(function() {
        spyOn(sourceCollection, 'fetch');
      });

      it('should fetch data from the source collection', function() {
        subsetCollection.fetch();

        expect(sourceCollection.fetch).toHaveBeenCalled();
      });

      it('should pass options on to the source collection\'s fetch method', function() {
        var OPTIONS_STUB = { STUB: 'OPTIONS_STUB' };

        subsetCollection.fetch(OPTIONS_STUB);

        expect(sourceCollection.fetch).toHaveBeenCalledWith(OPTIONS_STUB);
      });

      it('should return the source collection\'s promise to fetch', function() {
        var PROMISE_STUB = { STUB: 'PROMISE_STUB' };
        sourceCollection.fetch.andReturn(PROMISE_STUB);

        expect(subsetCollection.fetch()).toEqual(PROMISE_STUB);
      });

    });

  });

});

redpajama_set_name: RedPajamaGithub


text:
class AddTextToAnswers < ActiveRecord::Migration
  def change
    add_column :answers, :text, :string
    add_column :answers, :choice_id, :integer
    add_column :answers, :choice_ids, :text
  end
end


text:
import './Array.prototype.single';
import './Iterator.single'


text:
package memory

import (
	"sync"
	"time"

	"github.com/jaegertracing/jaeger/cmd/collector/app/sampling/model"
)

// SamplingStore is an in-memory store for sampling data
type SamplingStore struct {
	sync.RWMutex
	throughputs         []*storedThroughput
	probabilitiesAndQPS *storedServiceOperationProbabilitiesAndQPS
	maxBuckets          int
}

type storedThroughput struct {
	throughput []*model.Throughput
	time       time.Time
}

type storedServiceOperationProbabilitiesAndQPS struct {
	hostname      string
	probabilities model.ServiceOperationProbabilities
	qps           model.ServiceOperationQPS
	time          time.Time
}

// NewSamplingStore creates an in-memory sampling store.
func NewSamplingStore(maxBuckets int) *SamplingStore {
	return &SamplingStore{maxBuckets: maxBuckets}
}

// InsertThroughput implements samplingstore.Store#InsertThroughput.
func (ss *SamplingStore) InsertThroughput(throughput []*model.Throughput) error {
	ss.Lock()
	defer ss.Unlock()
	now := time.Now()
	ss.preprendThroughput(&storedThroughput{throughput, now})
	return nil
}

// GetThroughput implements samplingstore.Store#GetThroughput.
func (ss *SamplingStore) GetThroughput(start, end time.Time) ([]*model.Throughput, error) {
	ss.Lock()
	defer ss.Unlock()
	var retSlice []*model.Throughput
	for _, t := range ss.throughputs {
		if t.time.After(start) && (t.time.Before(end) || t.time.Equal(end)) {
			retSlice = append(retSlice, t.throughput...)
		}
	}
	return retSlice, nil
}

// InsertProbabilitiesAndQPS implements samplingstore.Store#InsertProbabilitiesAndQPS.
func (ss *SamplingStore) InsertProbabilitiesAndQPS(
	hostname string,
	probabilities model.ServiceOperationProbabilities,
	qps model.ServiceOperationQPS,
) error {
	ss.Lock()
	defer ss.Unlock()
	ss.probabilitiesAndQPS = &storedServiceOperationProbabilitiesAndQPS{hostname, probabilities, qps, time.Now()}
	return nil
}

// GetLatestProbabilities implements samplingstore.Store#GetLatestProbabilities.
func (ss *SamplingStore) GetLatestProbabilities() (model.ServiceOperationProbabilities, error) {
	ss.Lock()
	defer ss.Unlock()
	if ss.probabilitiesAndQPS != nil {
		return ss.probabilitiesAndQPS.probabilities, nil
	}
	return model.ServiceOperationProbabilities{}, nil
}

func (ss *SamplingStore) preprendThroughput(throughput *storedThroughput) {
	ss.throughputs = append([]*storedThroughput{throughput}, ss.throughputs...)
	if len(ss.throughputs) > ss.maxBuckets {
		ss.throughputs = ss.throughputs[0:ss.maxBuckets]
	}
}


text:
package com.ibm.watson.discovery.v1.model;

import static org.testng.Assert.*;

import com.ibm.cloud.sdk.core.service.model.FileWithMetadata;
import com.ibm.watson.discovery.v1.utils.TestUtilities;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import org.testng.annotations.Test;

/** Unit test class for the SourceOptionsFolder model. */
public class SourceOptionsFolderTest {
  final HashMap<String, InputStream> mockStreamMap = TestUtilities.createMockStreamMap();
  final List<FileWithMetadata> mockListFileWithMetadata =
      TestUtilities.creatMockListFileWithMetadata();

  @Test
  public void testSourceOptionsFolder() throws Throwable {
    SourceOptionsFolder sourceOptionsFolderModel =
        new SourceOptionsFolder.Builder()
            .ownerUserId("testString")
            .folderId("testString")
            .limit(Long.valueOf("26"))
            .build();
    assertEquals(sourceOptionsFolderModel.ownerUserId(), "testString");
    assertEquals(sourceOptionsFolderModel.folderId(), "testString");
    assertEquals(sourceOptionsFolderModel.limit(), Long.valueOf("26"));

    String json = TestUtilities.serialize(sourceOptionsFolderModel);

    SourceOptionsFolder sourceOptionsFolderModelNew =
        TestUtilities.deserialize(json, SourceOptionsFolder.class);
    assertTrue(sourceOptionsFolderModelNew instanceof SourceOptionsFolder);
    assertEquals(sourceOptionsFolderModelNew.ownerUserId(), "testString");
    assertEquals(sourceOptionsFolderModelNew.folderId(), "testString");
    assertEquals(sourceOptionsFolderModelNew.limit(), Long.valueOf("26"));
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testSourceOptionsFolderError() throws Throwable {
    new SourceOptionsFolder.Builder().build();
  }
}


text:
@class BSBserValues;
@class BSBserWriter;
@class IOSByteArray;
@class ImActorModelEntityContentInternalLocalFastThumb;

@interface ImActorModelEntityContentInternalLocalVideo : ImActorModelEntityContentInternalLocalDocument

#pragma mark Public

- (instancetype)initWithBSBserValues:(BSBserValues *)values;

- (instancetype)initWithByteArray:(IOSByteArray *)data;

- (instancetype)initWithNSString:(NSString *)fileName
                    withNSString:(NSString *)fileDescriptor
                         withInt:(jint)fileSize
                    withNSString:(NSString *)mimeType
withImActorModelEntityContentInternalLocalFastThumb:(ImActorModelEntityContentInternalLocalFastThumb *)fastThumb
                         withInt:(jint)w
                         withInt:(jint)h
                         withInt:(jint)duration;

- (jint)getDuration;

- (jint)getH;

- (jint)getW;

- (void)parseWithBSBserValues:(BSBserValues *)values;

- (void)serializeWithBSBserWriter:(BSBserWriter *)writer;

@end

J2OBJC_EMPTY_STATIC_INIT(ImActorModelEntityContentInternalLocalVideo)

FOUNDATION_EXPORT void ImActorModelEntityContentInternalLocalVideo_initWithNSString_withNSString_withInt_withNSString_withImActorModelEntityContentInternalLocalFastThumb_withInt_withInt_withInt_(ImActorModelEntityContentInternalLocalVideo *self, NSString *fileName, NSString *fileDescriptor, jint fileSize, NSString *mimeType, ImActorModelEntityContentInternalLocalFastThumb *fastThumb, jint w, jint h, jint duration);

FOUNDATION_EXPORT ImActorModelEntityContentInternalLocalVideo *new_ImActorModelEntityContentInternalLocalVideo_initWithNSString_withNSString_withInt_withNSString_withImActorModelEntityContentInternalLocalFastThumb_withInt_withInt_withInt_(NSString *fileName, NSString *fileDescriptor, jint fileSize, NSString *mimeType, ImActorModelEntityContentInternalLocalFastThumb *fastThumb, jint w, jint h, jint duration) NS_RETURNS_RETAINED;

FOUNDATION_EXPORT void ImActorModelEntityContentInternalLocalVideo_initWithByteArray_(ImActorModelEntityContentInternalLocalVideo *self, IOSByteArray *data);

FOUNDATION_EXPORT ImActorModelEntityContentInternalLocalVideo *new_ImActorModelEntityContentInternalLocalVideo_initWithByteArray_(IOSByteArray *data) NS_RETURNS_RETAINED;

FOUNDATION_EXPORT void ImActorModelEntityContentInternalLocalVideo_initWithBSBserValues_(ImActorModelEntityContentInternalLocalVideo *self, BSBserValues *values);

FOUNDATION_EXPORT ImActorModelEntityContentInternalLocalVideo *new_ImActorModelEntityContentInternalLocalVideo_initWithBSBserValues_(BSBserValues *values) NS_RETURNS_RETAINED;

J2OBJC_TYPE_LITERAL_HEADER(ImActorModelEntityContentInternalLocalVideo)

#endif // _ImActorModelEntityContentInternalLocalVideo_H_


text:
package metadata

import (
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strings"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fieldpath"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	utilErrors "github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/mount"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
	"github.com/golang/glog"
)

// ProbeVolumePlugins is the entry point for plugin detection in a package.
func ProbeVolumePlugins() []volume.VolumePlugin {
	return []volume.VolumePlugin{&metadataPlugin{}}
}

const (
	metadataPluginName = "kubernetes.io/metadata"
)

// metadataPlugin implements the VolumePlugin interface.
type metadataPlugin struct {
	host volume.VolumeHost
}

func (plugin *metadataPlugin) Init(host volume.VolumeHost) {
	plugin.host = host
}

func (plugin *metadataPlugin) Name() string {
	return metadataPluginName
}

func (plugin *metadataPlugin) CanSupport(spec *volume.Spec) bool {
	return spec.VolumeSource.Metadata != nil
}

func (plugin *metadataPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions, mounter mount.Interface) (volume.Builder, error) {
	return plugin.newBuilderInternal(spec, pod, opts, mounter)
}

func (plugin *metadataPlugin) newBuilderInternal(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions, mounter mount.Interface) (volume.Builder, error) {
	v := &metadataVolume{volName: spec.Name,
		pod:     pod,
		plugin:  plugin,
		opts:    &opts,
		mounter: mounter}
	v.fieldReferenceFileNames = make(map[string]string)
	for _, fileInfo := range spec.VolumeSource.Metadata.Items {
		v.fieldReferenceFileNames[fileInfo.FieldRef.FieldPath] = fileInfo.Name
	}
	return v, nil
}

func (plugin *metadataPlugin) NewCleaner(volName string, podUID types.UID, mounter mount.Interface) (volume.Cleaner, error) {
	return plugin.newCleanerInternal(volName, podUID, mounter)
}

func (plugin *metadataPlugin) newCleanerInternal(volName string, podUID types.UID, mounter mount.Interface) (volume.Cleaner, error) {
	return &metadataVolume{volName: volName,
		pod:     &api.Pod{ObjectMeta: api.ObjectMeta{UID: podUID}},
		plugin:  plugin,
		mounter: mounter}, nil
}

// metadataVolume handles retrieving metadata from the API server
// and placing them into the volume on the host.
type metadataVolume struct {
	volName                 string
	fieldReferenceFileNames map[string]string
	pod                     *api.Pod
	plugin                  *metadataPlugin
	opts                    *volume.VolumeOptions
	mounter                 mount.Interface
}

// This is the spec for the volume that this plugin wraps.
var wrappedVolumeSpec = &volume.Spec{
	Name:         "not-used",
	VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{Medium: api.StorageMediumMemory}},
}

// IsReadOnly exposes if the volume is read only.
// TODO: is this ok to always return true?
func (m *metadataVolume) IsReadOnly() bool {
	return true
}

// SetUp puts in place the volume plugin.
// This function is not idempotent by design. We want the data to be refreshed periodically.
// The internal sync interval of kubelet will drive the refresh of data.
func (m *metadataVolume) SetUp() error {
	return m.SetUpAt(m.GetPath())
}

func (m *metadataVolume) SetUpAt(dir string) error {
	glog.V(3).Infof("Setting up a metadata volume %v for pod %v at %v", m.volName, m.pod.UID, dir)
	// Wrap EmptyDir,let it do the setup.
	wrapped, err := m.plugin.host.NewWrapperBuilder(wrappedVolumeSpec, m.pod, *m.opts, m.mounter)
	if err != nil {
		return err
	}
	if err := wrapped.SetUpAt(dir); err != nil {
		return err
	}

	data := make(map[string]string)
	if err := m.collectData(&data); err != nil {
		return err
	}

	// files are fully regenerated only if requested metadata changed
	if m.isDataChanged(&data) {
		err = m.writeData(&data)
	}
	return err
}

// collectData collects requested metadata in data map.
// Map's key is the requested name of file to dump
// Map's value is the (sorted) content of the field to be dumped in the file.
func (m *metadataVolume) collectData(data *map[string]string) error {
	errlist := []error{}
	for fieldReference, fileName := range m.fieldReferenceFileNames {
		if values, err := fieldpath.ExtractFieldPathAsString(m.pod, fieldReference); err != nil {
			glog.Error(err)
			errlist = append(errlist, err)
		} else {
			(*data)[fileName] = sortLines(values)
		}
	}
	return utilErrors.NewAggregate(errlist)
}

// isDataChanged iterate over all the entries to check wether at least one
// file needs to be updated.
func (m *metadataVolume) isDataChanged(data *map[string]string) bool {
	for fileName, values := range *data {
		if isFileToGenerate(path.Join(m.GetPath(), fileName), values) {
			return true
		}
	}
	return false
}

// isFileToGenerate compares actual file with the new values. If
// different (or the file does not exist) return true
func isFileToGenerate(fileName, values string) bool {
	if _, err := os.Lstat(fileName); os.IsNotExist(err) {
		return true
	}
	return readFile(fileName) != values
}

const currentDir = ".current"
const currentTmpDir = ".current_tmp"

// writeData writes requested metadata in specified files.
//
// The file visible in this volume are symlinks to files in the '.current'
// directory. Actual files are stored in an hidden timestamped directory which is
// symlinked to by '.current'. The timestamped directory and '.current' symlink
// are created in the plugin root dir.  This scheme allows the files to be
// atomically updated by changing the target of the '.current' symlink.  When new
// data is available:
//
// 1.  A new timestamped dir is created by writeDataInTimestampDir
// 2.  Symlinks for new files are created if needed
// 3.  The previous timestamped directory is detected reading the '.current' symlink
// 4.  In case no symlink exists then it's created and func returns (first execution)
// 5.  In case symlink exists a new temporary symlink is created .current_tmp
// 6.  .current_tmp is renamed to .current
// 7.  The previous timestamped directory is removed
func (m *metadataVolume) writeData(data *map[string]string) error {
	var timestampDir string
	var err error
	timestampDir, err = m.writeDataInTimestampDir(data)
	if err != nil {
		glog.Error(err)
		return err
	}
	// update symbolic links for relative paths
	if err = m.updateSymlinksToCurrentDir(); err != nil {
		os.RemoveAll(timestampDir)
		glog.Error(err)
		return err
	}

	_, timestampDirBaseName := filepath.Split(timestampDir)
	var oldTimestampDirectory string
	oldTimestampDirectory, err = os.Readlink(path.Join(m.GetPath(), currentDir))
	if err != nil {
		if os.IsNotExist(err) { // no link to currentDir so creates it
			err = os.Symlink(timestampDirBaseName, path.Join(m.GetPath(), currentDir))
		}
		return err // in any cases return
	}

	// nominal case: link to currentDir exists create the link to currentTmpDir
	if err = os.Symlink(timestampDirBaseName, path.Join(m.GetPath(), currentTmpDir)); err != nil {
		os.RemoveAll(timestampDir)
		glog.Error(err)
		return err
	}

	// Rename the symbolic link currentTmpDir to currentDir
	if err = os.Rename(path.Join(m.GetPath(), currentTmpDir), path.Join(m.GetPath(), currentDir)); err != nil {
		// in case of error remove latest data and currentTmpDir
		os.Remove(path.Join(m.GetPath(), currentTmpDir))
		os.RemoveAll(timestampDir)
		glog.Error(err)
		return err
	}
	// Remove oldTimestampDirectory
	if len(oldTimestampDirectory) > 0 {
		if e := os.RemoveAll(path.Join(m.GetPath(), oldTimestampDirectory)); e != nil {
			glog.Error(e)
			return e
		}
	}
	return nil
}

// writeDataInTimestampDir writes the latest data into a new temporary directory with a timestamp.
func (m *metadataVolume) writeDataInTimestampDir(data *map[string]string) (string, error) {
	errlist := []error{}
	timestampDir, err := ioutil.TempDir(m.GetPath(), "."+time.Now().Format("2006_01_02_15_04_05"))
	for fileName, values := range *data {
		fullPathFile := path.Join(timestampDir, fileName)
		dir, _ := filepath.Split(fullPathFile)
		if err = os.MkdirAll(dir, os.ModePerm); err != nil {
			return "", err
		}
		if e := ioutil.WriteFile(fullPathFile, []byte(values), 0644); e != nil {
			glog.Error(e)
			errlist = append(errlist, err)
		}
	}
	return timestampDir, utilErrors.NewAggregate(errlist)
}

// updateSymlinksToCurrentDir creates the relative symlinks for all the files configured in this volume.
// If the directory in a file path does not exist, it is created.
func (m *metadataVolume) updateSymlinksToCurrentDir() error {
	for _, f := range m.fieldReferenceFileNames {
		dir, _ := filepath.Split(f)
		nbOfSubdir := 0
		if len(dir) > 0 {
			nbOfSubdir = len(strings.Split(dir, "/")) - 1
			if e := os.MkdirAll(path.Join(m.GetPath(), dir), os.ModePerm); e != nil {
				return e
			}
		}
		if _, e := os.Readlink(path.Join(m.GetPath(), f)); e != nil {
			// link does not exist create it
			if e := os.Symlink(path.Join(strings.Repeat("../", nbOfSubdir)+currentDir, f), path.Join(m.GetPath(), f)); e != nil {
				return e
			}
		}
	}
	return nil
}

// readFile reads the file at the given path and returns the content as a string.
func readFile(path string) string {
	if data, err := ioutil.ReadFile(path); err == nil {
		return string(data)
	}
	return ""
}

// sortLines sorts the strings generated from map based metadata
// (annotations and labels)
func sortLines(values string) string {
	splitted := strings.Split(values, "\n")
	sort.Strings(splitted)
	return strings.Join(splitted, "\n")
}

func (m *metadataVolume) GetPath() string {
	return m.plugin.host.GetPodVolumeDir(m.pod.UID, util.EscapeQualifiedNameForDisk(metadataPluginName), m.volName)
}

func (m *metadataVolume) TearDown() error {
	return m.TearDownAt(m.GetPath())
}

func (m *metadataVolume) TearDownAt(dir string) error {
	glog.V(3).Infof("Tearing down volume %v for pod %v at %v", m.volName, m.pod.UID, dir)

	// Wrap EmptyDir, let it do the teardown.
	wrapped, err := m.plugin.host.NewWrapperCleaner(wrappedVolumeSpec, m.pod.UID, m.mounter)
	if err != nil {
		return err
	}
	return wrapped.TearDownAt(dir)
}

func (m *metadataVolume) getMetaDir() string {
	return path.Join(m.plugin.host.GetPodPluginDir(m.pod.UID, util.EscapeQualifiedNameForDisk(metadataPluginName)), m.volName)
}


text:
 var unauthorizedTest = require("../../unauthorized-test-factory");
 unauthorizedTest({
     uri: "/sales/deal-tracking-deals"
 });


text:
<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ Copyright 2013 the original author or authors.
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~        http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>rest-assured-parent</artifactId>
        <groupId>io.rest-assured</groupId>
        <version>3.0.3-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>modules</artifactId>
    <packaging>pom</packaging>
    <name>REST Assured Modules</name>
    <modules>
        <module>json-schema-validator</module>
        <module>spring-mock-mvc</module>
        <module>scala-support</module>
    </modules>
</project>


text:
from azure.cli.core.commands import LongRunningOperation

def _last_segment(resource_id):
    return resource_id.split('/')[-1] if resource_id else None

_units = [(1024 * 1024 * 1024 * 1024, 'TB'),
          (1024 * 1024 * 1024, 'GB'),
          (1024 * 1024, 'MB'),
          (1024, 'kB'),
          (1, 'B')]

def _bytes_to_friendly_string(b):
    '''
    Formats the specified integer count of bytes as a friendly string
    with units, e.g. 1024 -> "1kB"
    '''

    # Find the largest unit that evenly divides the input
    unit = next(u for u in _units if (b % u[0]) == 0)

    # Format the value with the chosen unit
    return str((b // unit[0])) + unit[1]

class LongRunningOperationResultTransform(LongRunningOperation):  # pylint: disable=too-few-public-methods
    '''
    Long-running operation poller that also transforms the json response.
    '''
    def __init__(self, cli_ctx, transform_func):
        super(LongRunningOperationResultTransform, self).__init__(cli_ctx)
        self._transform_func = transform_func

    def __call__(self, result):
        '''
        Function call operator which will do polling (if necessary)
        and then transforms the result.
        '''

        if result is None:
            return None

        from azure.cli.core.util import poller_classes
        if isinstance(result, poller_classes()):
            # Poll for long-running operation result result by calling base class
            result = super(LongRunningOperationResultTransform, self).__call__(result)

        # Apply transform function
        return self._transform_func(result)

def _apply_format(result, format_group):
    '''
    Applies the specified format_group function to the single result or list of results.
    '''

    # Optionally grab internal 'value' array
    if 'value' in result and isinstance(result['value'], list):
        result = result['value']

    # Get list of results, or make singleton list from single list
    obj_list = result if isinstance(result, list) else [result]

    # Apply format function to list
    return [format_group(item) for item in obj_list]

###############################################
#                sql instance-pool            #
###############################################

def instance_pool_table_format(result):
    '''
    Formats an instance pool or list of instance pools as summary results for display with "-o table".
    '''
    def _instance_pool_table_format(result):
        '''
        Formats an instance pool or list of instance pools as summary results for display with "-o table".
        '''
        from collections import OrderedDict
        sku = result['sku']
        return OrderedDict([
            ('name', result['name']),
            ('resourceGroup', result['resourceGroup']),
            ('location', result['location']),
            ('Capacity', result['vCores']),
            ('SKU Family', sku['family']),
            ('SKU Tier', sku['tier']),
            ('Tags', str(result['tags']) if result['tags'] else '')
        ])

    return _apply_format(result, _instance_pool_table_format)

###############################################
#                sql server                   #
###############################################

def usage_table_format(result):
    '''
    Formats a usage or list of usage as summary results for display with "-o table".
    '''

    def _usage_table_format(result):
        '''
        Formats a usage as summary results for display with "-o table".
        '''
        from collections import OrderedDict

        return OrderedDict([
            ('name', result['name']),
            ('displayName', result['displayName']),
            ('currentValue', result['currentValue']),
            ('limit', result['limit']),
            ('unit', result['unit'])
        ])

    return _apply_format(result, _usage_table_format)

###############################################
#                sql db                       #
###############################################

#####
#           sql db transformers for json
#####

def db_list_transform(results):
    '''
    Transforms the json response for a list of databases.
    '''

    return [db_transform(r) for r in results]

def db_transform(result):
    '''
    Transforms the json response for a database.
    '''

    # Add properties in order to improve backwards compatibility with api-version 2014-04-01
    result.edition = result.sku.tier
    result.elastic_pool_name = _last_segment(result.elastic_pool_id)

    # rename ledger setting name
    if hasattr(result, 'is_ledger_on'):
        result.ledger_on = result.is_ledger_on
        del result.is_ledger_on

    if hasattr(result, 'storage_account_type'):
        result.backupStorageRedundancy = _get_external_backup_storage_redundancy(result.storage_account_type)
        del result.storage_account_type

    return result

def _get_external_backup_storage_redundancy(self):
    return {
        'lrs': 'Local',
        'grs': 'Geo',
        'zrs': 'Zone'
    }.get(self.lower(), 'Invalid')

#####
#           sql db table formatters
#####

def db_table_format(result):
    '''
    Formats a database or list of databases as summary results for display with "-o table".
    '''

    def _db_table_format(result):
        '''
        Formats a single database as summary results for display with "-o table".
        '''
        from collections import OrderedDict

        return OrderedDict([
            ('name', result['name']),
            ('tier', result['sku']['tier']),
            ('family', result['sku']['family'] or ' '),
            ('capacity', result['sku']['capacity'] or ' '),
            ('maxSize', _bytes_to_friendly_string(result['maxSizeBytes'])),
            ('elasticPool', _last_segment(result['elasticPoolId']) or ' '),
        ])

    return _apply_format(result, _db_table_format)

def db_edition_table_format(editions):
    '''
    Formats a list of database editions as summary results for display with "-o table".
    '''

    return list(_db_edition_table_format(editions))

def _db_edition_table_format(editions):
    '''
    Formats a database edition as summary results for display with "-o table".
    '''
    from .custom import is_available
    from collections import OrderedDict

    for e in editions:
        for slo in e['supportedServiceLevelObjectives']:
            sku = slo['sku']
            yield OrderedDict([
                ('serviceObjective', slo['name']),
                ('sku', sku['name']),
                ('edition', e['name']),
                # Dummy ' ' value ensures that value is not skipped, which
                # would cause the column to not show up in the correct order
                ('family', sku['family'] or ' '),
                ('capacity', sku['capacity']),
                ('unit', slo['performanceLevel']['unit']),
                ('available', is_available(slo['status'])),
            ])

###############################################
#                sql elastic-pool             #
###############################################

#####
#           sql elastic-pool transformers for json
#####

def elastic_pool_list_transform(results):
    return [elastic_pool_transform(r) for r in results]

def elastic_pool_transform(result):
    '''
    Transforms the json response for an elastic pool.
    '''

    # Add properties in order to improve backwards compatibility with api-version 2014-04-01
    result.edition = result.sku.tier
    result.storageMb = result.max_size_bytes / 1024 / 1024

    is_dtu = result.sku.tier in (
        'Basic',
        'Standard',
        'Premium')

    result.dtu = result.sku.capacity if is_dtu else None
    result.database_dtu_min = int(result.per_database_settings.min_capacity) if is_dtu else None
    result.database_dtu_max = int(result.per_database_settings.max_capacity) if is_dtu else None

    return result

#####
#           sql elastic-pool table formatters
#####

def elastic_pool_table_format(result):
    '''
    Formats a single or list of elastic pools as summary results for display with "-o table".
    '''

    def _elastic_pool_table_format(result):
        '''
        Formats a single elastic pool as summary results for display with "-o table".
        '''
        from collections import OrderedDict

        return OrderedDict([
            ('name', result['name']),
            ('tier', result['sku']['tier']),
            ('family', result['sku']['family'] or ' '),
            ('capacity', result['sku']['capacity'] or ' '),
            ('maxSize', _bytes_to_friendly_string(result['maxSizeBytes']))
        ])

    return _apply_format(result, _elastic_pool_table_format)

def elastic_pool_edition_table_format(editions):
    '''
    Formats a list of elastic pool editions as summary results for display with "-o table".
    '''

    return list(_elastic_pool_edition_table_format(editions))

def _elastic_pool_edition_table_format(editions):
    '''
    Formats an elastic pool editions as summary results for display with "-o table".
    '''
    from collections import OrderedDict
    from .custom import is_available

    for e in editions:
        for slo in e['supportedElasticPoolPerformanceLevels']:
            sku = slo['sku']
            yield OrderedDict([
                ('sku', sku['name']),
                ('edition', e['name']),
                # Dummy ' ' value ensures that value is not skipped, which
                # would cause the column to not show up in the correct order
                ('family', sku['family'] or ' '),
                ('capacity', sku['capacity']),
                ('unit', slo['performanceLevel']['unit']),
                ('available', is_available(slo['status'])),
            ])

###############################################
#                sql server                   #
###############################################

def server_table_format(result):
    '''
    Formats a server or list of servers as summary results for display with "-o table".
    '''

    def _server_table_format(result):
        '''
        Formats a server as summary results for display with "-o table".
        '''
        from collections import OrderedDict

        return OrderedDict([
            ('name', result['name']),
            ('resourceGroup', result['resourceGroup']),
            ('location', result['location']),
            ('administratorLogin', result['administratorLogin'])
        ])

    return _apply_format(result, _server_table_format)

###############################################
#                sql server firewall-rule     #
###############################################

def firewall_rule_table_format(result):
    '''
    Formats a single or list of server firewall rules as summary results for display with "-o table".
    '''

    def _firewall_rule_table_format(result):
        '''
        Formats a server firewall rule as summary results for display with "-o table".
        '''
        from collections import OrderedDict

        return OrderedDict([
            ('name', result['name']),
            ('startIpAddress', result['startIpAddress']),
            ('endIpAddress', result['endIpAddress'])
        ])

    return _apply_format(result, _firewall_rule_table_format)

########################################################
#            sql server outbound-firewall-rule         #
########################################################

def outbound_firewall_rule_table_format(result):
    '''
    Formats a single or list of server outbound firewall rules as summary results for display with "-o table".
    '''

    def _outbound_firewall_rule_table_format(result):
        '''
        Formats a server outbound firewall rule as summary results for display with "-o table".
        '''
        from collections import OrderedDict

        return OrderedDict([
            ('resourceGroupName', result['resourceGroupName']),
            ('serverName', result['serverName']),
            ('outboundRuleFqdn', result['outboundRuleFqdn'])
        ])

    return _apply_format(result, _outbound_firewall_rule_table_format)


text:
.class public abstract Landroid/app/job/IJobScheduler$Stub;
.super Landroid/os/Binder;
.source "IJobScheduler.java"

# interfaces
.implements Landroid/app/job/IJobScheduler;

# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
    value = Landroid/app/job/IJobScheduler;
.end annotation

.annotation system Ldalvik/annotation/InnerClass;
    accessFlags = 0x409
    name = "Stub"
.end annotation

.annotation system Ldalvik/annotation/MemberClasses;
    value = {
        Landroid/app/job/IJobScheduler$Stub$Proxy;
    }
.end annotation

# static fields
.field private static final DESCRIPTOR:Ljava/lang/String; = "android.app.job.IJobScheduler"

.field static final TRANSACTION_cancel:I = 0x2

.field static final TRANSACTION_cancelAll:I = 0x3

.field static final TRANSACTION_getAllPendingJobs:I = 0x4

.field static final TRANSACTION_schedule:I = 0x1

# direct methods
.method public constructor <init>()V
    .locals 1

    .prologue
    .line 17
    invoke-direct {p0}, Landroid/os/Binder;-><init>()V

    .line 19
    const-string/jumbo v0, "android.app.job.IJobScheduler"

    invoke-virtual {p0, p0, v0}, Landroid/app/job/IJobScheduler$Stub;->attachInterface(Landroid/os/IInterface;Ljava/lang/String;)V

    .line 17
    return-void
.end method

.method public static asInterface(Landroid/os/IBinder;)Landroid/app/job/IJobScheduler;
    .locals 2
    .param p0, "obj"    # Landroid/os/IBinder;

    .prologue
    const/4 v1, 0x0

    .line 27
    if-nez p0, :cond_0

    .line 28
    return-object v1

    .line 30
    :cond_0
    const-string/jumbo v1, "android.app.job.IJobScheduler"

    invoke-interface {p0, v1}, Landroid/os/IBinder;->queryLocalInterface(Ljava/lang/String;)Landroid/os/IInterface;

    move-result-object v0

    .line 31
    .local v0, "iin":Landroid/os/IInterface;
    if-eqz v0, :cond_1

    instance-of v1, v0, Landroid/app/job/IJobScheduler;

    if-eqz v1, :cond_1

    .line 32
    check-cast v0, Landroid/app/job/IJobScheduler;

    .end local v0    # "iin":Landroid/os/IInterface;
    return-object v0

    .line 34
    .restart local v0    # "iin":Landroid/os/IInterface;
    :cond_1
    new-instance v1, Landroid/app/job/IJobScheduler$Stub$Proxy;

    invoke-direct {v1, p0}, Landroid/app/job/IJobScheduler$Stub$Proxy;-><init>(Landroid/os/IBinder;)V

    return-object v1
.end method

# virtual methods
.method public asBinder()Landroid/os/IBinder;
    .locals 0

    .prologue
    .line 38
    return-object p0
.end method

.method public onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
    .locals 6
    .param p1, "code"    # I
    .param p2, "data"    # Landroid/os/Parcel;
    .param p3, "reply"    # Landroid/os/Parcel;
    .param p4, "flags"    # I
    .annotation system Ldalvik/annotation/Throws;
        value = {
            Landroid/os/RemoteException;
        }
    .end annotation

    .prologue
    const/4 v5, 0x1

    .line 42
    sparse-switch p1, :sswitch_data_0

    .line 89
    invoke-super {p0, p1, p2, p3, p4}, Landroid/os/Binder;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z

    move-result v4

    return v4

    .line 46
    :sswitch_0
    const-string/jumbo v4, "android.app.job.IJobScheduler"

    invoke-virtual {p3, v4}, Landroid/os/Parcel;->writeString(Ljava/lang/String;)V

    .line 47
    return v5

    .line 51
    :sswitch_1
    const-string/jumbo v4, "android.app.job.IJobScheduler"

    invoke-virtual {p2, v4}, Landroid/os/Parcel;->enforceInterface(Ljava/lang/String;)V

    .line 53
    invoke-virtual {p2}, Landroid/os/Parcel;->readInt()I

    move-result v4

    if-eqz v4, :cond_0

    .line 54
    sget-object v4, Landroid/app/job/JobInfo;->CREATOR:Landroid/os/Parcelable$Creator;

    invoke-interface {v4, p2}, Landroid/os/Parcelable$Creator;->createFromParcel(Landroid/os/Parcel;)Ljava/lang/Object;

    move-result-object v1

    check-cast v1, Landroid/app/job/JobInfo;

    .line 59
    :goto_0
    invoke-virtual {p0, v1}, Landroid/app/job/IJobScheduler$Stub;->schedule(Landroid/app/job/JobInfo;)I

    move-result v2

    .line 60
    .local v2, "_result":I
    invoke-virtual {p3}, Landroid/os/Parcel;->writeNoException()V

    .line 61
    invoke-virtual {p3, v2}, Landroid/os/Parcel;->writeInt(I)V

    .line 62
    return v5

    .line 57
    .end local v2    # "_result":I
    :cond_0
    const/4 v1, 0x0

    .local v1, "_arg0":Landroid/app/job/JobInfo;
    goto :goto_0

    .line 66
    .end local v1    # "_arg0":Landroid/app/job/JobInfo;
    :sswitch_2
    const-string/jumbo v4, "android.app.job.IJobScheduler"

    invoke-virtual {p2, v4}, Landroid/os/Parcel;->enforceInterface(Ljava/lang/String;)V

    .line 68
    invoke-virtual {p2}, Landroid/os/Parcel;->readInt()I

    move-result v0

    .line 69
    .local v0, "_arg0":I
    invoke-virtual {p0, v0}, Landroid/app/job/IJobScheduler$Stub;->cancel(I)V

    .line 70
    invoke-virtual {p3}, Landroid/os/Parcel;->writeNoException()V

    .line 71
    return v5

    .line 75
    .end local v0    # "_arg0":I
    :sswitch_3
    const-string/jumbo v4, "android.app.job.IJobScheduler"

    invoke-virtual {p2, v4}, Landroid/os/Parcel;->enforceInterface(Ljava/lang/String;)V

    .line 76
    invoke-virtual {p0}, Landroid/app/job/IJobScheduler$Stub;->cancelAll()V

    .line 77
    invoke-virtual {p3}, Landroid/os/Parcel;->writeNoException()V

    .line 78
    return v5

    .line 82
    :sswitch_4
    const-string/jumbo v4, "android.app.job.IJobScheduler"

    invoke-virtual {p2, v4}, Landroid/os/Parcel;->enforceInterface(Ljava/lang/String;)V

    .line 83
    invoke-virtual {p0}, Landroid/app/job/IJobScheduler$Stub;->getAllPendingJobs()Ljava/util/List;

    move-result-object v3

    .line 84
    .local v3, "_result":Ljava/util/List;, "Ljava/util/List<Landroid/app/job/JobInfo;>;"
    invoke-virtual {p3}, Landroid/os/Parcel;->writeNoException()V

    .line 85
    invoke-virtual {p3, v3}, Landroid/os/Parcel;->writeTypedList(Ljava/util/List;)V

    .line 86
    return v5

    .line 42
    :sswitch_data_0
    .sparse-switch
        0x1 -> :sswitch_1
        0x2 -> :sswitch_2
        0x3 -> :sswitch_3
        0x4 -> :sswitch_4
        0x5f4e5446 -> :sswitch_0
    .end sparse-switch
.end method


text:
export const FORM_TAG_CHANGE = 'FORM_TAG_CHANGE'
export const FORM_TAG_REMOVE = 'FORM_TAG_REMOVE'

export const formTagAdd = (e) => ({
  type: FORM_TAG_CHANGE,
  payload: {
    name: e.target.name,
    value: e.target.value.trim()
  }
})

export const formTagRemove = (name, value) => ({
  type: FORM_TAG_REMOVE,
  payload: {
    name,
    value
  }
})