// Path: core/src/main/java/com/caseystella/analytics/DataPoint.java
// public class DataPoint {
//     private long timestamp;
//     private double value;
//     private Map<String, String> metadata;
//     private String source;
// 
//     public DataPoint() {
// 
//     }
// 
//     public DataPoint(long timestamp, double value, Map<String, String> metadata, String source) {
//         this.timestamp = timestamp;
//         this.value = value;
//         this.metadata = metadata;
//         this.source = source;
//     }
// 
//     public String getSource() {
//         return source;
//     }
// 
//     public void setSource(String source) {
//         this.source = source;
//     }
// 
// 
// 
//     public long getTimestamp() {
//         return timestamp;
//     }
// 
//     public void setTimestamp(long timestamp) {
//         this.timestamp = timestamp;
//     }
// 
//     public double getValue() {
//         return value;
//     }
// 
//     public void setValue(double value) {
//         this.value = value;
//     }
// 
//     public Map<String, String> getMetadata() {
//         return metadata;
//     }
// 
//     public void setMetadata(Map<String, String> metadata) {
//         this.metadata = metadata;
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         DataPoint dataPoint = (DataPoint) o;
// 
//         if (getTimestamp() != dataPoint.getTimestamp()) return false;
//         if (Double.compare(dataPoint.getValue(), getValue()) != 0) return false;
//         if (getMetadata() != null ? !getMetadata().equals(dataPoint.getMetadata()) : dataPoint.getMetadata() != null)
//             return false;
//         return source != null ? source.equals(dataPoint.source) : dataPoint.source == null;
// 
//     }
// 
//     @Override
//     public int hashCode() {
//         int result;
//         long temp;
//         result = (int) (getTimestamp() ^ (getTimestamp() >>> 32));
//         temp = Double.doubleToLongBits(getValue());
//         result = 31 * result + (int) (temp ^ (temp >>> 32));
//         result = 31 * result + (getMetadata() != null ? getMetadata().hashCode() : 0);
//         result = 31 * result + (source != null ? source.hashCode() : 0);
//         return result;
//     }
//     @Override
//     public String toString() {
//         return "(" +
//                 "timestamp=" + timestamp +
//                 ", value=" + value +
//                 ", metadata=" + metadata +
//                 ", source=" + source+
//                 ')';
//     }
// 
// }
// 
// Path: core/src/main/java/com/caseystella/analytics/distribution/TimeRange.java
// public interface TimeRange extends Range<Long>{
// 
// }
// 
// Path: core/src/main/java/com/caseystella/analytics/timeseries/TimeseriesDatabaseHandler.java
// public interface TimeseriesDatabaseHandler extends Serializable {
//     void persist(String metric, DataPoint pt, Map<String, String> tags, Function<Object, Void> callback);
//     List<DataPoint> retrieve(String metric, DataPoint pt, TimeRange range, Map<String, String> filter, int maxPts);
//     void configure(Map<String, Object> config);
// }


import com.caseystella.analytics.DataPoint;
import com.caseystella.analytics.distribution.TimeRange;
import com.caseystella.analytics.timeseries.TimeseriesDatabaseHandler;
import com.google.common.base.Function;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Sets;
import java.util.*;
    private static boolean mapContains(Map<String, String> tags, Map<String, String> filter) {
        if(filter != null) {
            for (Map.Entry<String, String> kv : filter.entrySet()) {
                Object o = tags.get(kv.getKey());
                if (o == null || !o.equals(kv.getValue())) {
                    return false;
                }
            }
        }
        return true;
    }
    @Override
    public List<DataPoint> retrieve(String metric, DataPoint pt, TimeRange range, Map<String, String> filter, int maxPts) {
        synchronized(_sync) {
            NavigableSet<DataPoint> tsMap = backingStore.get(metric);
            List<DataPoint> ret = new ArrayList<>();
            for (DataPoint pts : tsMap.subSet(getLeftEndpoint(range.getBegin())
                                                              , true
                                                              , getRightEndpoint(pt.getTimestamp())
                                                              , true
                                                              )) {
                if(pts.getTimestamp() != pt.getTimestamp() && pts.getValue() != pt.getValue() && mapContains(pts.getMetadata(), filter)) {
                    ret.add(pts);
                }
            }
            return ret;
        }
    }

    public static Collection<DataPoint> getAllPoints(String metric) {
// Path: core/src/main/java/com/caseystella/analytics/DataPoint.java
// public class DataPoint {
//     private long timestamp;
//     private double value;
//     private Map<String, String> metadata;
//     private String source;
// 
//     public DataPoint() {
// 
//     }
// 
//     public DataPoint(long timestamp, double value, Map<String, String> metadata, String source) {
//         this.timestamp = timestamp;
//         this.value = value;
//         this.metadata = metadata;
//         this.source = source;
//     }
// 
//     public String getSource() {
//         return source;
//     }
// 
//     public void setSource(String source) {
//         this.source = source;
//     }
// 
// 
// 
//     public long getTimestamp() {
//         return timestamp;
//     }
// 
//     public void setTimestamp(long timestamp) {
//         this.timestamp = timestamp;
//     }
// 
//     public double getValue() {
//         return value;
//     }
// 
//     public void setValue(double value) {
//         this.value = value;
//     }
// 
//     public Map<String, String> getMetadata() {
//         return metadata;
//     }
// 
//     public void setMetadata(Map<String, String> metadata) {
//         this.metadata = metadata;
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         DataPoint dataPoint = (DataPoint) o;
// 
//         if (getTimestamp() != dataPoint.getTimestamp()) return false;
//         if (Double.compare(dataPoint.getValue(), getValue()) != 0) return false;
//         if (getMetadata() != null ? !getMetadata().equals(dataPoint.getMetadata()) : dataPoint.getMetadata() != null)
//             return false;
//         return source != null ? source.equals(dataPoint.source) : dataPoint.source == null;
// 
//     }
// 
//     @Override
//     public int hashCode() {
//         int result;
//         long temp;
//         result = (int) (getTimestamp() ^ (getTimestamp() >>> 32));
//         temp = Double.doubleToLongBits(getValue());
//         result = 31 * result + (int) (temp ^ (temp >>> 32));
//         result = 31 * result + (getMetadata() != null ? getMetadata().hashCode() : 0);
//         result = 31 * result + (source != null ? source.hashCode() : 0);
//         return result;
//     }
//     @Override
//     public String toString() {
//         return "(" +
//                 "timestamp=" + timestamp +
//                 ", value=" + value +
//                 ", metadata=" + metadata +
//                 ", source=" + source+
//                 ')';
//     }
// 
// }
// 
// Path: core/src/main/java/com/caseystella/analytics/distribution/TimeRange.java
// public interface TimeRange extends Range<Long>{
// 
// }
// 
// Path: core/src/main/java/com/caseystella/analytics/timeseries/TimeseriesDatabaseHandler.java
// public interface TimeseriesDatabaseHandler extends Serializable {
//     void persist(String metric, DataPoint pt, Map<String, String> tags, Function<Object, Void> callback);
//     List<DataPoint> retrieve(String metric, DataPoint pt, TimeRange range, Map<String, String> filter, int maxPts);
//     void configure(Map<String, Object> config);
// }


// Path: core/src/main/java/com/caseystella/analytics/timeseries/inmemory/InMemoryTimeSeriesDB.java
import com.caseystella.analytics.DataPoint;
import com.caseystella.analytics.distribution.TimeRange;
import com.caseystella.analytics.timeseries.TimeseriesDatabaseHandler;
import com.google.common.base.Function;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Sets;
import java.util.*;

    private static boolean mapContains(Map<String, String> tags, Map<String, String> filter) {
        if(filter != null) {
            for (Map.Entry<String, String> kv : filter.entrySet()) {
                Object o = tags.get(kv.getKey());
                if (o == null || !o.equals(kv.getValue())) {
                    return false;
                }
            }
        }
        return true;
    }
    @Override
    public List<DataPoint> retrieve(String metric, DataPoint pt, TimeRange range, Map<String, String> filter, int maxPts) {
        synchronized(_sync) {
            NavigableSet<DataPoint> tsMap = backingStore.get(metric);
            List<DataPoint> ret = new ArrayList<>();
            for (DataPoint pts : tsMap.subSet(getLeftEndpoint(range.getBegin())
                                                              , true
                                                              , getRightEndpoint(pt.getTimestamp())
                                                              , true
                                                              )) {
                if(pts.getTimestamp() != pt.getTimestamp() && pts.getValue() != pt.getValue() && mapContains(pts.getMetadata(), filter)) {
                    ret.add(pts);
                }
            }
            return ret;
        }
    }

    public static Collection<DataPoint> getAllPoints(String metric) {
        synchronized (_sync) {