// Path: pearl/src/main/java/com/hanuor/pearl/volleysingleton/Cache.java
// public interface Cache {
//     /**
//      * Retrieves an entry from the cache.
//      * @param key Cache key
//      * @return An {@link Entry} or null in the event of a cache miss
//      */
//     public Entry get(String key);
// 
//     /**
//      * Adds or replaces an entry to the cache.
//      * @param key Cache key
//      * @param entry Data to store and metadata for cache coherency, TTL, etc.
//      */
//     public void put(String key, Entry entry);
// 
//     /**
//      * Performs any potentially long-running actions needed to initialize the cache;
//      * will be called from a worker thread.
//      */
//     public void initialize();
// 
//     /**
//      * Invalidates an entry in the cache.
//      * @param key Cache key
//      * @param fullExpire True to fully expire the entry, false to soft expire
//      */
//     public void invalidate(String key, boolean fullExpire);
// 
//     /**
//      * Removes an entry from the cache.
//      * @param key Cache key
//      */
//     public void remove(String key);
// 
//     /**
//      * Empties the cache.
//      */
//     public void clear();
// 
//     /**
//      * Data and metadata for an entry returned by the cache.
//      */
//     public static class Entry {
//         /** The data returned from cache. */
//         public byte[] data;
// 
//         /** ETag for cache coherency. */
//         public String etag;
// 
//         /** Date of this response as reported by the server. */
//         public long serverDate;
// 
//         /** The last modified date for the requested object. */
//         public long lastModified;
// 
//         /** TTL for this record. */
//         public long ttl;
// 
//         /** Soft TTL for this record. */
//         public long softTtl;
// 
//         /** Immutable response headers as received from server; must be non-null. */
//         public Map<String, String> responseHeaders = Collections.emptyMap();
// 
//         /** True if the entry is expired. */
//         public boolean isExpired() {
//             return this.ttl < System.currentTimeMillis();
//         }
// 
//         /** True if a refresh is needed from the original data source. */
//         public boolean refreshNeeded() {
//             return this.softTtl < System.currentTimeMillis();
//         }
//     }
// 
// }
// 
// Path: pearl/src/main/java/com/hanuor/pearl/volleysingleton/NetworkResponse.java
// public class NetworkResponse {
//     /**
//      * Creates a new network response.
//      * @param statusCode the HTTP status code
//      * @param data Response body
//      * @param headers Headers returned with this response, or null for none
//      * @param notModified True if the server returned a 304 and the data was already in cache
//      * @param networkTimeMs Round-trip network time to receive network response
//      */
//     public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
//             boolean notModified, long networkTimeMs) {
//         this.statusCode = statusCode;
//         this.data = data;
//         this.headers = headers;
//         this.notModified = notModified;
//         this.networkTimeMs = networkTimeMs;
//     }
// 
//     public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
//             boolean notModified) {
//         this(statusCode, data, headers, notModified, 0);
//     }
// 
//     public NetworkResponse(byte[] data) {
//         this(HttpStatus.SC_OK, data, Collections.<String, String>emptyMap(), false, 0);
//     }
// 
//     public NetworkResponse(byte[] data, Map<String, String> headers) {
//         this(HttpStatus.SC_OK, data, headers, false, 0);
//     }
// 
//     /** The HTTP status code. */
//     public final int statusCode;
// 
//     /** Raw data from this response. */
//     public final byte[] data;
// 
//     /** Response headers. */
//     public final Map<String, String> headers;
// 
//     /** True if the server returned a 304 (Not Modified). */
//     public final boolean notModified;
// 
//     /** Network roundtrip time in milliseconds. */
//     public final long networkTimeMs;
// }


import com.hanuor.pearl.volleysingleton.Cache;
import com.hanuor.pearl.volleysingleton.NetworkResponse;
import org.apache.http.impl.cookie.DateParseException;
import org.apache.http.impl.cookie.DateUtils;
import org.apache.http.protocol.HTTP;
import java.util.Map;
                    mustRevalidate = true;
                }
            }
        }

        headerValue = headers.get("Expires");
        if (headerValue != null) {
            serverExpires = parseDateAsEpoch(headerValue);
        }

        headerValue = headers.get("Last-Modified");
        if (headerValue != null) {
            lastModified = parseDateAsEpoch(headerValue);
        }

        serverEtag = headers.get("ETag");

        // Cache-Control takes precedence over an Expires header, even if both exist and Expires
        // is more restrictive.
        if (hasCacheControl) {
            softExpire = now + maxAge * 1000;
            finalExpire = mustRevalidate
                    ? softExpire
                    : softExpire + staleWhileRevalidate * 1000;
        } else if (serverDate > 0 && serverExpires >= serverDate) {
            // Default semantic for Expire header in HTTP specification is softExpire.
            softExpire = now + (serverExpires - serverDate);
            finalExpire = softExpire;
        }

// Path: pearl/src/main/java/com/hanuor/pearl/volleysingleton/Cache.java
// public interface Cache {
//     /**
//      * Retrieves an entry from the cache.
//      * @param key Cache key
//      * @return An {@link Entry} or null in the event of a cache miss
//      */
//     public Entry get(String key);
// 
//     /**
//      * Adds or replaces an entry to the cache.
//      * @param key Cache key
//      * @param entry Data to store and metadata for cache coherency, TTL, etc.
//      */
//     public void put(String key, Entry entry);
// 
//     /**
//      * Performs any potentially long-running actions needed to initialize the cache;
//      * will be called from a worker thread.
//      */
//     public void initialize();
// 
//     /**
//      * Invalidates an entry in the cache.
//      * @param key Cache key
//      * @param fullExpire True to fully expire the entry, false to soft expire
//      */
//     public void invalidate(String key, boolean fullExpire);
// 
//     /**
//      * Removes an entry from the cache.
//      * @param key Cache key
//      */
//     public void remove(String key);
// 
//     /**
//      * Empties the cache.
//      */
//     public void clear();
// 
//     /**
//      * Data and metadata for an entry returned by the cache.
//      */
//     public static class Entry {
//         /** The data returned from cache. */
//         public byte[] data;
// 
//         /** ETag for cache coherency. */
//         public String etag;
// 
//         /** Date of this response as reported by the server. */
//         public long serverDate;
// 
//         /** The last modified date for the requested object. */
//         public long lastModified;
// 
//         /** TTL for this record. */
//         public long ttl;
// 
//         /** Soft TTL for this record. */
//         public long softTtl;
// 
//         /** Immutable response headers as received from server; must be non-null. */
//         public Map<String, String> responseHeaders = Collections.emptyMap();
// 
//         /** True if the entry is expired. */
//         public boolean isExpired() {
//             return this.ttl < System.currentTimeMillis();
//         }
// 
//         /** True if a refresh is needed from the original data source. */
//         public boolean refreshNeeded() {
//             return this.softTtl < System.currentTimeMillis();
//         }
//     }
// 
// }
// 
// Path: pearl/src/main/java/com/hanuor/pearl/volleysingleton/NetworkResponse.java
// public class NetworkResponse {
//     /**
//      * Creates a new network response.
//      * @param statusCode the HTTP status code
//      * @param data Response body
//      * @param headers Headers returned with this response, or null for none
//      * @param notModified True if the server returned a 304 and the data was already in cache
//      * @param networkTimeMs Round-trip network time to receive network response
//      */
//     public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
//             boolean notModified, long networkTimeMs) {
//         this.statusCode = statusCode;
//         this.data = data;
//         this.headers = headers;
//         this.notModified = notModified;
//         this.networkTimeMs = networkTimeMs;
//     }
// 
//     public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
//             boolean notModified) {
//         this(statusCode, data, headers, notModified, 0);
//     }
// 
//     public NetworkResponse(byte[] data) {
//         this(HttpStatus.SC_OK, data, Collections.<String, String>emptyMap(), false, 0);
//     }
// 
//     public NetworkResponse(byte[] data, Map<String, String> headers) {
//         this(HttpStatus.SC_OK, data, headers, false, 0);
//     }
// 
//     /** The HTTP status code. */
//     public final int statusCode;
// 
//     /** Raw data from this response. */
//     public final byte[] data;
// 
//     /** Response headers. */
//     public final Map<String, String> headers;
// 
//     /** True if the server returned a 304 (Not Modified). */
//     public final boolean notModified;
// 
//     /** Network roundtrip time in milliseconds. */
//     public final long networkTimeMs;
// }


// Path: pearl/src/main/java/com/hanuor/pearl/toolbox/HttpHeaderParser.java
import com.hanuor.pearl.volleysingleton.Cache;
import com.hanuor.pearl.volleysingleton.NetworkResponse;
import org.apache.http.impl.cookie.DateParseException;
import org.apache.http.impl.cookie.DateUtils;
import org.apache.http.protocol.HTTP;
import java.util.Map;

                    mustRevalidate = true;
                }
            }
        }

        headerValue = headers.get("Expires");
        if (headerValue != null) {
            serverExpires = parseDateAsEpoch(headerValue);
        }

        headerValue = headers.get("Last-Modified");
        if (headerValue != null) {
            lastModified = parseDateAsEpoch(headerValue);
        }

        serverEtag = headers.get("ETag");

        // Cache-Control takes precedence over an Expires header, even if both exist and Expires
        // is more restrictive.
        if (hasCacheControl) {
            softExpire = now + maxAge * 1000;
            finalExpire = mustRevalidate
                    ? softExpire
                    : softExpire + staleWhileRevalidate * 1000;
        } else if (serverDate > 0 && serverExpires >= serverDate) {
            // Default semantic for Expire header in HTTP specification is softExpire.
            softExpire = now + (serverExpires - serverDate);
            finalExpire = softExpire;
        }

        Cache.Entry entry = new Cache.Entry();