docs: public static TopologyMaster.MetricResponse toProtobuf(MetricResponse response,
                                                           MetricRequest request) {
      TopologyMaster.MetricResponse.Builder builder =
          TopologyMaster.MetricResponse.newBuilder();
      builder.setInterval((request.getEndTime() - request.getStartTime()) / 1000); // in seconds
  
      // default OK if we have response to build already
      builder.setStatus(Common.Status.newBuilder().setStatus(Common.StatusCode.OK));
  
      // instanceId -> [metricName -> metricValue]
      // componentName is ignored, since there is only one component in the query
      Map<String, Map<String, List<MetricTimeRangeValue>>> aggregation =
          new HashMap<>();
      for (MetricDatum datum : response.getMetricList()) {
        String instanceId = datum.getInstanceId();
        String metricName = datum.getMetricName();
        List<MetricTimeRangeValue> metricValue = datum.getMetricValue();
        // prepare
        if (!aggregation.containsKey(instanceId)) {
          aggregation.put(instanceId, new HashMap<String, List<MetricTimeRangeValue>>());
        }
        if (!aggregation.get(instanceId).containsKey(metricName)) {
          aggregation.get(instanceId).put(metricName, new ArrayList<MetricTimeRangeValue>());
        }
        // aggregate
        aggregation.get(instanceId).get(metricName).addAll(metricValue);
      }
  
      // add TaskMetric
      for (String instanceId : aggregation.keySet()) {
        TopologyMaster.MetricResponse.TaskMetric.Builder taskMetricBuilder =
            TopologyMaster.MetricResponse.TaskMetric.newBuilder();
  
        taskMetricBuilder.setInstanceId(instanceId);
        // add IndividualMetric
        for (String metricName : aggregation.get(instanceId).keySet()) {
          TopologyMaster.MetricResponse.IndividualMetric.Builder individualMetricBuilder =
              TopologyMaster.MetricResponse.IndividualMetric.newBuilder();
  
          individualMetricBuilder.setName(metricName);
          // add value|IntervalValue
          List<MetricTimeRangeValue> list = aggregation.get(instanceId).get(metricName);
          if (list.size() == 1) {
            individualMetricBuilder.setValue(list.get(0).getValue());
          } else {
            for (MetricTimeRangeValue v : list) {
              TopologyMaster.MetricResponse.IndividualMetric.IntervalValue.Builder
                  intervalValueBuilder =
                  TopologyMaster.MetricResponse.IndividualMetric.IntervalValue.newBuilder();
  
              intervalValueBuilder.setValue(v.getValue());
              intervalValueBuilder.setInterval(TopologyMaster.MetricInterval.newBuilder()
                  .setStart(v.getStartTime()).setEnd(v.getEndTime()));
  
              individualMetricBuilder.addIntervalValues(intervalValueBuilder);
            }// end IntervalValue
          }
  
          taskMetricBuilder.addMetric(individualMetricBuilder);
        }// end IndividualMetric
  
        builder.addMetric(taskMetricBuilder);
      }// end TaskMetric
  
      return builder.build();
    }