// Path: library/src/main/java/com/danikula/videocache/file/FileNameGenerator.java
// public interface FileNameGenerator {
// 
//     String generate(String url);
// 
// }
// 
// Path: library/src/main/java/com/danikula/videocache/headers/EmptyHeadersInjector.java
// public class EmptyHeadersInjector implements HeaderInjector {
// 
//     @Override
//     public Map<String, String> addHeaders(String url) {
//         return new HashMap<>();
//     }
// 
// }
// 
// Path: library/src/main/java/com/danikula/videocache/headers/HeaderInjector.java
// public interface HeaderInjector {
// 
//     /**
//      * Adds headers to server's requests for corresponding url.
//      *
//      * @param url an url headers will be added for
//      * @return a map with headers, where keys are header's names, and values are header's values. {@code null} is not acceptable!
//      */
//     Map<String, String> addHeaders(String url);
// 
// }
// 
// Path: library/src/main/java/com/danikula/videocache/sourcestorage/SourceInfoStorage.java
// public interface SourceInfoStorage {
// 
//     SourceInfo get(String url);
// 
//     void put(String url, SourceInfo sourceInfo);
// 
//     void release();
// }
// 
// Path: library/src/main/java/com/danikula/videocache/sourcestorage/SourceInfoStorageFactory.java
// public class SourceInfoStorageFactory {
// 
//     public static SourceInfoStorage newSourceInfoStorage(Context context) {
//         return new DatabaseSourceInfoStorage(context);
//     }
// 
//     public static SourceInfoStorage newEmptySourceInfoStorage() {
//         return new NoSourceInfoStorage();
//     }
// }
// 
// Path: library/src/main/java/com/danikula/videocache/Preconditions.java
// public static void checkAllNotNull(Object... references) {
//     for (Object reference : references) {
//         if (reference == null) {
//             throw new NullPointerException();
//         }
//     }
// }
// 
// Path: library/src/main/java/com/danikula/videocache/Preconditions.java
// public static <T> T checkNotNull(T reference) {
//     if (reference == null) {
//         throw new NullPointerException();
//     }
//     return reference;
// }


import android.content.Context;
import android.net.Uri;
import com.danikula.videocache.file.DiskUsage;
import com.danikula.videocache.file.FileNameGenerator;
import com.danikula.videocache.file.Md5FileNameGenerator;
import com.danikula.videocache.file.TotalCountLruDiskUsage;
import com.danikula.videocache.file.TotalSizeLruDiskUsage;
import com.danikula.videocache.headers.EmptyHeadersInjector;
import com.danikula.videocache.headers.HeaderInjector;
import com.danikula.videocache.sourcestorage.SourceInfoStorage;
import com.danikula.videocache.sourcestorage.SourceInfoStorageFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static com.danikula.videocache.Preconditions.checkAllNotNull;
import static com.danikula.videocache.Preconditions.checkNotNull;
     * <p>
     * Calling this method has same effect as calling {@link #getProxyUrl(String, boolean)} with 2nd parameter set to {@code true}.
     *
     * @param url a url to file that should be cached.
     * @return a wrapped by proxy url if file is not fully cached or url pointed to cache file otherwise.
     */
    public String getProxyUrl(String url) {
        return getProxyUrl(url, true);
    }

    /**
     * Returns url that wrap original url and should be used for client (MediaPlayer, ExoPlayer, etc).
     * <p>
     * If parameter {@code allowCachedFileUri} is {@code true} and file for this url is fully cached
     * (it means method {@link #isCached(String)} returns {@code true}) then file:// uri to cached file will be returned.
     *
     * @param url                a url to file that should be cached.
     * @param allowCachedFileUri {@code true} if allow to return file:// uri if url is fully cached
     * @return a wrapped by proxy url if file is not fully cached or url pointed to cache file otherwise (if {@code allowCachedFileUri} is {@code true}).
     */
    public String getProxyUrl(String url, boolean allowCachedFileUri) {
        if (allowCachedFileUri && isCached(url)) {
            File cacheFile = getCacheFile(url);
            touchFileSafely(cacheFile);
            return Uri.fromFile(cacheFile).toString();
        }
        return isAlive() ? appendToProxyUrl(url) : url;
    }

    public void registerCacheListener(CacheListener cacheListener, String url) {
// Path: library/src/main/java/com/danikula/videocache/file/FileNameGenerator.java
// public interface FileNameGenerator {
// 
//     String generate(String url);
// 
// }
// 
// Path: library/src/main/java/com/danikula/videocache/headers/EmptyHeadersInjector.java
// public class EmptyHeadersInjector implements HeaderInjector {
// 
//     @Override
//     public Map<String, String> addHeaders(String url) {
//         return new HashMap<>();
//     }
// 
// }
// 
// Path: library/src/main/java/com/danikula/videocache/headers/HeaderInjector.java
// public interface HeaderInjector {
// 
//     /**
//      * Adds headers to server's requests for corresponding url.
//      *
//      * @param url an url headers will be added for
//      * @return a map with headers, where keys are header's names, and values are header's values. {@code null} is not acceptable!
//      */
//     Map<String, String> addHeaders(String url);
// 
// }
// 
// Path: library/src/main/java/com/danikula/videocache/sourcestorage/SourceInfoStorage.java
// public interface SourceInfoStorage {
// 
//     SourceInfo get(String url);
// 
//     void put(String url, SourceInfo sourceInfo);
// 
//     void release();
// }
// 
// Path: library/src/main/java/com/danikula/videocache/sourcestorage/SourceInfoStorageFactory.java
// public class SourceInfoStorageFactory {
// 
//     public static SourceInfoStorage newSourceInfoStorage(Context context) {
//         return new DatabaseSourceInfoStorage(context);
//     }
// 
//     public static SourceInfoStorage newEmptySourceInfoStorage() {
//         return new NoSourceInfoStorage();
//     }
// }
// 
// Path: library/src/main/java/com/danikula/videocache/Preconditions.java
// public static void checkAllNotNull(Object... references) {
//     for (Object reference : references) {
//         if (reference == null) {
//             throw new NullPointerException();
//         }
//     }
// }
// 
// Path: library/src/main/java/com/danikula/videocache/Preconditions.java
// public static <T> T checkNotNull(T reference) {
//     if (reference == null) {
//         throw new NullPointerException();
//     }
//     return reference;
// }


// Path: library/src/main/java/com/danikula/videocache/HttpProxyCacheServer.java
import android.content.Context;
import android.net.Uri;
import com.danikula.videocache.file.DiskUsage;
import com.danikula.videocache.file.FileNameGenerator;
import com.danikula.videocache.file.Md5FileNameGenerator;
import com.danikula.videocache.file.TotalCountLruDiskUsage;
import com.danikula.videocache.file.TotalSizeLruDiskUsage;
import com.danikula.videocache.headers.EmptyHeadersInjector;
import com.danikula.videocache.headers.HeaderInjector;
import com.danikula.videocache.sourcestorage.SourceInfoStorage;
import com.danikula.videocache.sourcestorage.SourceInfoStorageFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static com.danikula.videocache.Preconditions.checkAllNotNull;
import static com.danikula.videocache.Preconditions.checkNotNull;

     * <p>
     * Calling this method has same effect as calling {@link #getProxyUrl(String, boolean)} with 2nd parameter set to {@code true}.
     *
     * @param url a url to file that should be cached.
     * @return a wrapped by proxy url if file is not fully cached or url pointed to cache file otherwise.
     */
    public String getProxyUrl(String url) {
        return getProxyUrl(url, true);
    }

    /**
     * Returns url that wrap original url and should be used for client (MediaPlayer, ExoPlayer, etc).
     * <p>
     * If parameter {@code allowCachedFileUri} is {@code true} and file for this url is fully cached
     * (it means method {@link #isCached(String)} returns {@code true}) then file:// uri to cached file will be returned.
     *
     * @param url                a url to file that should be cached.
     * @param allowCachedFileUri {@code true} if allow to return file:// uri if url is fully cached
     * @return a wrapped by proxy url if file is not fully cached or url pointed to cache file otherwise (if {@code allowCachedFileUri} is {@code true}).
     */
    public String getProxyUrl(String url, boolean allowCachedFileUri) {
        if (allowCachedFileUri && isCached(url)) {
            File cacheFile = getCacheFile(url);
            touchFileSafely(cacheFile);
            return Uri.fromFile(cacheFile).toString();
        }
        return isAlive() ? appendToProxyUrl(url) : url;
    }

    public void registerCacheListener(CacheListener cacheListener, String url) {
        checkAllNotNull(cacheListener, url);