// Path: src/main/java/be/fror/common/io/ByteSource.java
// public abstract class ByteSource {
// 
//   protected ByteSource() {
//   }
// 
//   public final InputStream openStream() throws UncheckedIOException {
//     try {
//       return doOpenStream();
//     } catch (IOException e) {
//       throw new UncheckedIOException(e);
//     }
//   }
// 
//   protected abstract InputStream doOpenStream() throws IOException;
// 
//   public CharSource asCharSource(Charset charset) {
//     return new AsCharSource(checkNotNull(charset));
//   }
// 
//   private class AsCharSource extends CharSource {
// 
//     private final Charset charset;
// 
//     private AsCharSource(Charset charset) {
//       this.charset = charset;
//     }
// 
//     @Override
//     protected Reader doOpenStream() throws IOException {
//       return new InputStreamReader(ByteSource.this.doOpenStream(), charset);
//     }
// 
//     @Override
//     public String toString() {
//       return ByteSource.this.toString() + ".asCharSource(" + charset + ")";
//     }
// 
//   }
// 
//   public long copyTo(ByteSink sink) throws UncheckedIOException {
//     try (InputStream in = doOpenStream();
//         OutputStream out = sink.doOpenStream()) {
//       return ByteStreams.copy(in, out);
//     } catch (IOException e) {
//       throw new UncheckedIOException(e);
//     }
// 
//   }
// 
//   public byte[] read() throws UncheckedIOException {
//     try (InputStream in = doOpenStream()) {
//       return ByteStreams.toByteArray(in);
//     } catch (IOException e) {
//       throw new UncheckedIOException(e);
//     }
//   }
// 
//   public static ByteSource wrap(byte[] bytes) {
//     return new ByteArrayByteSource(checkNotNull(bytes));
//   }
// 
//   private static class ByteArrayByteSource extends ByteSource {
// 
//     private final byte[] bytes;
// 
//     public ByteArrayByteSource(byte[] bytes) {
//       this.bytes = bytes;
//     }
// 
//     @Override
//     protected InputStream doOpenStream() throws IOException {
//       return new ByteArrayInputStream(bytes);
//     }
// 
//     @Override
//     public String toString() {
//       return "ByteSource.wrap(" + "bytes" + ")";
//     }
// 
//   }
// 
//   public static ByteSource empty() {
//     return EmptyByteSource.INSTANCE;
//   }
// 
//   private static final class EmptyByteSource extends ByteArrayByteSource {
// 
//     private static final EmptyByteSource INSTANCE = new EmptyByteSource();
// 
//     private EmptyByteSource() {
//       super(new byte[0]);
//     }
// 
//     @Override
//     public String toString() {
//       return "ByteSource.empty()";
//     }
//   }
// 
// }


import java.util.Map;
import java.util.Properties;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.nio.charset.StandardCharsets.UTF_16;
import static java.nio.charset.StandardCharsets.UTF_16BE;
import static java.nio.charset.StandardCharsets.UTF_16LE;
import static java.nio.charset.StandardCharsets.UTF_8;
import be.fror.common.io.ByteSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
/*
 * Copyright 2015 Olivier Grégoire.
 *
 * 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.
 */
package be.fror.common.resource;




/**
 * Tools for {@link ResourceLoader}, including static factory methods.
 *
 * @author Olivier Grégoire
 */
public final class ResourceLoaders {

  private ResourceLoaders() {
  }

  /**
   * Returns a {code ResourceLoader} able to load {@link Properties} using
   * {@link Properties#load(java.io.InputStream)}
   *
   * @return
   */
  public static ResourceLoader<Properties> propertiesLoader() {
    return InputStreamPropertiesLoader.PROPERTIES;
  }

  /**
   * Returns a {code ResourceLoader} able to load {@link Properties} using
   * {@link Properties#loadFromXML(java.io.InputStream)}
   *
   * @return
   */
  public static ResourceLoader<Properties> xmlPropertiesLoader() {
    return InputStreamPropertiesLoader.XML;
  }

  private static interface PropertiesLoader extends ResourceLoader<Properties> {

    @Override
    public default Properties load(ByteSource source) throws IOException {
      Properties properties = new Properties();
      load(properties, source);
      return properties;
    }

    public void load(Properties properties, ByteSource source) throws IOException;

  }

  private enum InputStreamPropertiesLoader implements PropertiesLoader {

    PROPERTIES {
          @Override
// Path: src/main/java/be/fror/common/io/ByteSource.java
// public abstract class ByteSource {
// 
//   protected ByteSource() {
//   }
// 
//   public final InputStream openStream() throws UncheckedIOException {
//     try {
//       return doOpenStream();
//     } catch (IOException e) {
//       throw new UncheckedIOException(e);
//     }
//   }
// 
//   protected abstract InputStream doOpenStream() throws IOException;
// 
//   public CharSource asCharSource(Charset charset) {
//     return new AsCharSource(checkNotNull(charset));
//   }
// 
//   private class AsCharSource extends CharSource {
// 
//     private final Charset charset;
// 
//     private AsCharSource(Charset charset) {
//       this.charset = charset;
//     }
// 
//     @Override
//     protected Reader doOpenStream() throws IOException {
//       return new InputStreamReader(ByteSource.this.doOpenStream(), charset);
//     }
// 
//     @Override
//     public String toString() {
//       return ByteSource.this.toString() + ".asCharSource(" + charset + ")";
//     }
// 
//   }
// 
//   public long copyTo(ByteSink sink) throws UncheckedIOException {
//     try (InputStream in = doOpenStream();
//         OutputStream out = sink.doOpenStream()) {
//       return ByteStreams.copy(in, out);
//     } catch (IOException e) {
//       throw new UncheckedIOException(e);
//     }
// 
//   }
// 
//   public byte[] read() throws UncheckedIOException {
//     try (InputStream in = doOpenStream()) {
//       return ByteStreams.toByteArray(in);
//     } catch (IOException e) {
//       throw new UncheckedIOException(e);
//     }
//   }
// 
//   public static ByteSource wrap(byte[] bytes) {
//     return new ByteArrayByteSource(checkNotNull(bytes));
//   }
// 
//   private static class ByteArrayByteSource extends ByteSource {
// 
//     private final byte[] bytes;
// 
//     public ByteArrayByteSource(byte[] bytes) {
//       this.bytes = bytes;
//     }
// 
//     @Override
//     protected InputStream doOpenStream() throws IOException {
//       return new ByteArrayInputStream(bytes);
//     }
// 
//     @Override
//     public String toString() {
//       return "ByteSource.wrap(" + "bytes" + ")";
//     }
// 
//   }
// 
//   public static ByteSource empty() {
//     return EmptyByteSource.INSTANCE;
//   }
// 
//   private static final class EmptyByteSource extends ByteArrayByteSource {
// 
//     private static final EmptyByteSource INSTANCE = new EmptyByteSource();
// 
//     private EmptyByteSource() {
//       super(new byte[0]);
//     }
// 
//     @Override
//     public String toString() {
//       return "ByteSource.empty()";
//     }
//   }
// 
// }


// Path: src/main/java/be/fror/common/resource/ResourceLoaders.java
import java.util.Map;
import java.util.Properties;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.nio.charset.StandardCharsets.UTF_16;
import static java.nio.charset.StandardCharsets.UTF_16BE;
import static java.nio.charset.StandardCharsets.UTF_16LE;
import static java.nio.charset.StandardCharsets.UTF_8;
import be.fror.common.io.ByteSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;

/*
 * Copyright 2015 Olivier Grégoire.
 *
 * 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.
 */
package be.fror.common.resource;




/**
 * Tools for {@link ResourceLoader}, including static factory methods.
 *
 * @author Olivier Grégoire
 */
public final class ResourceLoaders {

  private ResourceLoaders() {
  }

  /**
   * Returns a {code ResourceLoader} able to load {@link Properties} using
   * {@link Properties#load(java.io.InputStream)}
   *
   * @return
   */
  public static ResourceLoader<Properties> propertiesLoader() {
    return InputStreamPropertiesLoader.PROPERTIES;
  }

  /**
   * Returns a {code ResourceLoader} able to load {@link Properties} using
   * {@link Properties#loadFromXML(java.io.InputStream)}
   *
   * @return
   */
  public static ResourceLoader<Properties> xmlPropertiesLoader() {
    return InputStreamPropertiesLoader.XML;
  }

  private static interface PropertiesLoader extends ResourceLoader<Properties> {

    @Override
    public default Properties load(ByteSource source) throws IOException {
      Properties properties = new Properties();
      load(properties, source);
      return properties;
    }

    public void load(Properties properties, ByteSource source) throws IOException;

  }

  private enum InputStreamPropertiesLoader implements PropertiesLoader {

    PROPERTIES {
          @Override
          public void load(Properties properties, ByteSource source) throws IOException {