// Path: endpoints-control/src/main/java/com/google/api/control/model/Timestamps.java
// public final class Timestamps {
//   private static final int MILLIS_PER_SECOND = 1000;
//   private static final int NANOS_PER_MILLI = 1000000;
// 
//   private Timestamps() {}
// 
//   /**
//    * A {@code Comparator} of {@link Timestamp}
//    */
//   public static Comparator<Timestamp> COMPARATOR = new Comparator<Timestamp>() {
//     @Override
//     public int compare(Timestamp o1, Timestamp o2) {
//       int secondsOrder = Long.compare(o1.getSeconds(), o2.getSeconds());
//       if (secondsOrder != 0) {
//         return secondsOrder;
//       } else {
//         return Long.compare(o1.getNanos(), o2.getNanos());
//       }
//     }
//   };
// 
//   /**
//    * Obtain the current time from a {@link Clock}
//    *
//    * @param clock gives the current time
//    * @return a {@code Timestamp} corresponding to the ticker's current value
//    */
//   public static Timestamp now(Clock clock) {
//     return fromEpoch(clock.currentTimeMillis());
//   }
// 
//   /**
//    * Obtain the current time from the unix epoch
//    *
//    * @param epochMillis gives the current time in milliseconds since since the epoch
//    * @return a {@code Timestamp} corresponding to the ticker's current value
//    */
//   public static Timestamp fromEpoch(long epochMillis) {
//     return Timestamp
//         .newBuilder()
//         .setNanos((int) ((epochMillis % MILLIS_PER_SECOND) * NANOS_PER_MILLI))
//         .setSeconds(epochMillis / MILLIS_PER_SECOND)
//         .build();
//   }
// }


import com.google.api.MetricDescriptor.MetricKind;
import com.google.api.control.model.Timestamps;
import com.google.api.servicecontrol.v1.MetricValue;
import com.google.api.servicecontrol.v1.MetricValueSet;
import com.google.api.servicecontrol.v1.QuotaOperation;
import com.google.common.collect.Maps;
import com.google.common.flogger.FluentLogger;
import java.util.Map;
      MetricValue val = metricValueSets.get(mvSet.getMetricName());
      if (val == null) {
        metricValueSets.put(mvSet.getMetricName(), mvSet.getMetricValues(0));
      } else {
        metricValueSets.put(
            mvSet.getMetricName(),
            MetricValues.merge(MetricKind.DELTA, val, mvSet.getMetricValues(0)));
      }
    }
  }

  public QuotaOperation asQuotaOperation() {
    QuotaOperation.Builder op = this.op.clone().clearQuotaMetrics();
    for (Map.Entry<String, MetricValue> entry : metricValueSets.entrySet()) {
      op.addQuotaMetrics(MetricValueSet.newBuilder()
          .setMetricName(entry.getKey())
          .addMetricValues(entry.getValue()));
    }
    return op.build();
  }

  private MetricValue mergeDeltaMetricValue(MetricValue from, MetricValue to) {
    if (to.getValueCase() != from.getValueCase()) {
      log.atWarning().log("Could not merge different types of metric: %s, %s", from, to);
      return to;
    }

    MetricValue.Builder builder = to.toBuilder();
    if (from.hasStartTime()) {
      if (!to.hasStartTime() ||
// Path: endpoints-control/src/main/java/com/google/api/control/model/Timestamps.java
// public final class Timestamps {
//   private static final int MILLIS_PER_SECOND = 1000;
//   private static final int NANOS_PER_MILLI = 1000000;
// 
//   private Timestamps() {}
// 
//   /**
//    * A {@code Comparator} of {@link Timestamp}
//    */
//   public static Comparator<Timestamp> COMPARATOR = new Comparator<Timestamp>() {
//     @Override
//     public int compare(Timestamp o1, Timestamp o2) {
//       int secondsOrder = Long.compare(o1.getSeconds(), o2.getSeconds());
//       if (secondsOrder != 0) {
//         return secondsOrder;
//       } else {
//         return Long.compare(o1.getNanos(), o2.getNanos());
//       }
//     }
//   };
// 
//   /**
//    * Obtain the current time from a {@link Clock}
//    *
//    * @param clock gives the current time
//    * @return a {@code Timestamp} corresponding to the ticker's current value
//    */
//   public static Timestamp now(Clock clock) {
//     return fromEpoch(clock.currentTimeMillis());
//   }
// 
//   /**
//    * Obtain the current time from the unix epoch
//    *
//    * @param epochMillis gives the current time in milliseconds since since the epoch
//    * @return a {@code Timestamp} corresponding to the ticker's current value
//    */
//   public static Timestamp fromEpoch(long epochMillis) {
//     return Timestamp
//         .newBuilder()
//         .setNanos((int) ((epochMillis % MILLIS_PER_SECOND) * NANOS_PER_MILLI))
//         .setSeconds(epochMillis / MILLIS_PER_SECOND)
//         .build();
//   }
// }


// Path: endpoints-control/src/main/java/com/google/api/control/aggregator/QuotaOperationAggregator.java
import com.google.api.MetricDescriptor.MetricKind;
import com.google.api.control.model.Timestamps;
import com.google.api.servicecontrol.v1.MetricValue;
import com.google.api.servicecontrol.v1.MetricValueSet;
import com.google.api.servicecontrol.v1.QuotaOperation;
import com.google.common.collect.Maps;
import com.google.common.flogger.FluentLogger;
import java.util.Map;

      MetricValue val = metricValueSets.get(mvSet.getMetricName());
      if (val == null) {
        metricValueSets.put(mvSet.getMetricName(), mvSet.getMetricValues(0));
      } else {
        metricValueSets.put(
            mvSet.getMetricName(),
            MetricValues.merge(MetricKind.DELTA, val, mvSet.getMetricValues(0)));
      }
    }
  }

  public QuotaOperation asQuotaOperation() {
    QuotaOperation.Builder op = this.op.clone().clearQuotaMetrics();
    for (Map.Entry<String, MetricValue> entry : metricValueSets.entrySet()) {
      op.addQuotaMetrics(MetricValueSet.newBuilder()
          .setMetricName(entry.getKey())
          .addMetricValues(entry.getValue()));
    }
    return op.build();
  }

  private MetricValue mergeDeltaMetricValue(MetricValue from, MetricValue to) {
    if (to.getValueCase() != from.getValueCase()) {
      log.atWarning().log("Could not merge different types of metric: %s, %s", from, to);
      return to;
    }

    MetricValue.Builder builder = to.toBuilder();
    if (from.hasStartTime()) {
      if (!to.hasStartTime() ||
          Timestamps.COMPARATOR.compare(from.getStartTime(), to.getStartTime()) == -1) {