diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/ServletUtil.java b/src/main/java/gov/usgs/earthquake/nshmp/www/ServletUtil.java
index c3221f2448774d696ca5aec951739b7d6e89a2e7..a357ab271fa982e1d9e496c791811b6bcc7fdaac 100644
--- a/src/main/java/gov/usgs/earthquake/nshmp/www/ServletUtil.java
+++ b/src/main/java/gov/usgs/earthquake/nshmp/www/ServletUtil.java
@@ -17,6 +17,7 @@ import java.util.concurrent.Executors;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Stopwatch;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 import com.google.gson.Gson;
@@ -183,4 +184,21 @@ public class ServletUtil {
     return imt.toString();
   }
 
+  public static Object serverData(int threads, Stopwatch timer) {
+    return new Server(threads, timer);
+  }
+
+  private static class Server {
+
+    final int threads;
+    final String timer;
+    final String version;
+
+    Server(int threads, Stopwatch timer) {
+      this.threads = threads;
+      this.timer = timer.toString();
+      this.version = "TODO where to get version?";
+    }
+  }
+
 }
diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/DisaggService.java b/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/DisaggService.java
index cac2e3537b27518b4702e35ab7c6f98a14f285d9..55a955b99e72bdd7fb319115e7484fefed36433a 100644
--- a/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/DisaggService.java
+++ b/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/DisaggService.java
@@ -25,8 +25,7 @@ import gov.usgs.earthquake.nshmp.gmm.Imt;
 import gov.usgs.earthquake.nshmp.model.HazardModel;
 import gov.usgs.earthquake.nshmp.www.ResponseBody;
 import gov.usgs.earthquake.nshmp.www.ServletUtil;
-import gov.usgs.earthquake.nshmp.www.hazard.HazardService.UsageMetadata;
-import gov.usgs.earthquake.nshmp.www.meta.Metadata;
+import gov.usgs.earthquake.nshmp.www.hazard.HazardService.Metadata;
 import gov.usgs.earthquake.nshmp.www.meta.Parameter;
 import io.micronaut.http.HttpRequest;
 import io.micronaut.http.HttpResponse;
@@ -57,7 +56,7 @@ public final class DisaggService {
   /** HazardController.doGetMetadata() handler. */
   public static HttpResponse<String> getMetadata(HttpRequest<?> request) {
     var url = request.getUri().toString();
-    var usage = new UsageMetadata(ServletUtil.model());
+    var usage = new Metadata(ServletUtil.model());
     var response = ResponseBody.usage()
         .name(NAME)
         .url(url)
@@ -73,7 +72,7 @@ public final class DisaggService {
       throws InterruptedException, ExecutionException {
     var stopwatch = Stopwatch.createStarted();
     var disagg = calcDisaggIml(request);
-    var response = new ResponseBuilder()
+    var response = new Response.Builder()
         .timer(stopwatch)
         .request(request)
         .disagg(disagg)
@@ -93,7 +92,7 @@ public final class DisaggService {
       throws InterruptedException, ExecutionException {
     var stopwatch = Stopwatch.createStarted();
     var disagg = calcDisaggRp(request);
-    var response = new ResponseBuilder()
+    var response = new Response.Builder()
         .timer(stopwatch)
         .request(request)
         .disagg(disagg)
@@ -238,83 +237,82 @@ public final class DisaggService {
     }
   }
 
-  private static final class ResponseMetadata {
-    final Object server;
-    final String rlabel = "Closest Distance, rRup (km)";
-    final String mlabel = "Magnitude (Mw)";
-    final String εlabel = "% Contribution to Hazard";
-    final Object εbins;
-
-    ResponseMetadata(Object server, Object εbins) {
-      this.server = server;
-      this.εbins = εbins;
-    }
-  }
-
   private static final class Response {
-    final ResponseMetadata metadata;
+    final Response.Metadata metadata;
     final List<ImtDisagg> disaggs;
 
-    Response(ResponseMetadata metadata, List<ImtDisagg> disaggs) {
+    Response(Response.Metadata metadata, List<ImtDisagg> disaggs) {
       this.metadata = metadata;
       this.disaggs = disaggs;
     }
-  }
 
-  private static final class ImtDisagg {
-    final Parameter imt;
-    final Object data;
+    private static final class Metadata {
+      final Object server;
+      final String rlabel = "Closest Distance, rRup (km)";
+      final String mlabel = "Magnitude (Mw)";
+      final String εlabel = "% Contribution to Hazard";
+      final Object εbins;
 
-    ImtDisagg(Imt imt, Object data) {
-      this.imt = new Parameter(
-          ServletUtil.imtShortLabel(imt),
-          imt.name());
-      this.data = data;
+      Metadata(Object server, Object εbins) {
+        this.server = server;
+        this.εbins = εbins;
+      }
     }
-  }
 
-  private static final class ResponseBuilder {
+    private static final class Builder {
 
-    Stopwatch timer;
-    Optional<RequestRp> requestRp = Optional.empty();
-    Optional<RequestIml> requestIml = Optional.empty();
-    Disaggregation disagg;
+      Stopwatch timer;
+      Optional<RequestRp> requestRp = Optional.empty();
+      Optional<RequestIml> requestIml = Optional.empty();
+      Disaggregation disagg;
 
-    ResponseBuilder timer(Stopwatch timer) {
-      this.timer = timer;
-      return this;
-    }
+      Builder timer(Stopwatch timer) {
+        this.timer = timer;
+        return this;
+      }
 
-    ResponseBuilder request(Object request) {
-      if (request instanceof RequestRp) {
-        requestRp = Optional.of((RequestRp) request);
+      Builder request(Object request) {
+        if (request instanceof RequestRp) {
+          requestRp = Optional.of((RequestRp) request);
+          return this;
+        }
+        requestIml = Optional.of((RequestIml) request);
         return this;
       }
-      requestIml = Optional.of((RequestIml) request);
-      return this;
-    }
 
-    ResponseBuilder disagg(Disaggregation disagg) {
-      this.disagg = disagg;
-      return this;
-    }
+      Builder disagg(Disaggregation disagg) {
+        this.disagg = disagg;
+        return this;
+      }
 
-    Response build() {
+      Response build() {
 
-      Set<Imt> imts = requestRp.isPresent()
-          ? requestRp.orElseThrow().imts
-          : requestIml.orElseThrow().imls.keySet();
+        Set<Imt> imts = requestRp.isPresent()
+            ? requestRp.orElseThrow().imts
+            : requestIml.orElseThrow().imls.keySet();
 
-      List<ImtDisagg> disaggs = imts.stream()
-          .map(imt -> new ImtDisagg(imt, disagg.toJson(imt)))
-          .collect(toList());
+        List<ImtDisagg> disaggs = imts.stream()
+            .map(imt -> new ImtDisagg(imt, disagg.toJson(imt)))
+            .collect(toList());
 
-      Object server = Metadata.serverData(ServletUtil.THREAD_COUNT, timer);
+        Object server = ServletUtil.serverData(ServletUtil.THREAD_COUNT, timer);
 
-      return new Response(
-          new ResponseMetadata(server, disagg.εBins()),
-          disaggs);
+        return new Response(
+            new Response.Metadata(server, disagg.εBins()),
+            disaggs);
+      }
     }
   }
 
+  private static final class ImtDisagg {
+    final Parameter imt;
+    final Object data;
+
+    ImtDisagg(Imt imt, Object data) {
+      this.imt = new Parameter(
+          ServletUtil.imtShortLabel(imt),
+          imt.name());
+      this.data = data;
+    }
+  }
 }
diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/HazardService.java b/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/HazardService.java
index 556dffea9b78224b901546471b4692e2bd466234..fb51309a0025f353263aa7c060c978d261b05c4c 100644
--- a/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/HazardService.java
+++ b/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/HazardService.java
@@ -36,7 +36,6 @@ import gov.usgs.earthquake.nshmp.model.SourceType;
 import gov.usgs.earthquake.nshmp.www.ResponseBody;
 import gov.usgs.earthquake.nshmp.www.ServletUtil;
 import gov.usgs.earthquake.nshmp.www.meta.DoubleParameter;
-import gov.usgs.earthquake.nshmp.www.meta.Metadata;
 import gov.usgs.earthquake.nshmp.www.meta.Parameter;
 import gov.usgs.earthquake.nshmp.www.services.SourceServices.SourceModel;
 import io.micronaut.http.HttpRequest;
@@ -55,10 +54,12 @@ public final class HazardService {
   static final String NAME = "Hazard Service";
   static final Logger LOG = LoggerFactory.getLogger(HazardService.class);
 
+  private static final String TOTAL_KEY = "Total";
+
   /** HazardController.doGetUsage() handler. */
   public static HttpResponse<String> getMetadata(HttpRequest<?> request) {
     var url = request.getUri().toString();
-    var usage = new UsageMetadata(ServletUtil.model());
+    var usage = new Metadata(ServletUtil.model());
     var body = ResponseBody.usage()
         .name(NAME)
         .url(url)
@@ -74,7 +75,7 @@ public final class HazardService {
       throws InterruptedException, ExecutionException {
     var stopwatch = Stopwatch.createStarted();
     var hazard = calcHazard(request);
-    var response = new ResponseBuilder()
+    var response = new Response.Builder()
         .timer(stopwatch)
         .request(request)
         .hazard(hazard)
@@ -123,14 +124,14 @@ public final class HazardService {
     return future.get();
   }
 
-  static class UsageMetadata {
+  static class Metadata {
 
     final SourceModel model;
     final DoubleParameter longitude;
     final DoubleParameter latitude;
     final DoubleParameter vs30;
 
-    UsageMetadata(HazardModel model) {
+    Metadata(HazardModel model) {
       this.model = new SourceModel(model);
       // TODO need min max from model
       longitude = new DoubleParameter(
@@ -184,124 +185,124 @@ public final class HazardService {
     }
   }
 
-  private static final class ResponseMetadata {
-    final Object server;
-    final String xlabel = "Ground Motion (g)";
-    final String ylabel = "Annual Frequency of Exceedence";
-
-    ResponseMetadata(Object server) {
-      this.server = server;
-    }
-  }
-
   private static final class Response {
-    final ResponseMetadata metadata;
+
+    final Metadata metadata;
     final List<ImtCurves> hazardCurves;
 
-    Response(ResponseMetadata metadata, List<ImtCurves> hazardCurves) {
+    Response(Metadata metadata, List<ImtCurves> hazardCurves) {
       this.metadata = metadata;
       this.hazardCurves = hazardCurves;
     }
-  }
-
-  private static final class ImtCurves {
-    final Parameter imt;
-    final List<Curve> data;
-
-    ImtCurves(Imt imt, List<Curve> data) {
-      this.imt = new Parameter(ServletUtil.imtShortLabel(imt), imt.name());
-      this.data = data;
-    }
-  }
 
-  private static final class Curve {
-    final String component;
-    final XySequence values;
+    private static final class Metadata {
+      final Object server;
+      final String xlabel = "Ground Motion (g)";
+      final String ylabel = "Annual Frequency of Exceedence";
 
-    Curve(String component, XySequence values) {
-      this.component = component;
-      this.values = values;
+      Metadata(Object server) {
+        this.server = server;
+      }
     }
-  }
 
-  private static final String TOTAL_KEY = "Total";
+    private static final class Builder {
 
-  private static final class ResponseBuilder {
+      Stopwatch timer;
+      Request request;
+      Map<Imt, Map<SourceType, MutableXySequence>> componentMaps;
+      Map<Imt, MutableXySequence> totalMap;
 
-    Stopwatch timer;
-    Request request;
-    Map<Imt, Map<SourceType, MutableXySequence>> componentMaps;
-    Map<Imt, MutableXySequence> totalMap;
+      Builder timer(Stopwatch timer) {
+        this.timer = timer;
+        return this;
+      }
 
-    ResponseBuilder timer(Stopwatch timer) {
-      this.timer = timer;
-      return this;
-    }
+      Builder request(Request request) {
+        this.request = request;
+        return this;
+      }
 
-    ResponseBuilder request(Request request) {
-      this.request = request;
-      return this;
-    }
+      Builder hazard(Hazard hazard) {
+        // TODO necessary??
+        checkState(totalMap == null, "Hazard has already been added to this builder");
 
-    ResponseBuilder hazard(Hazard hazard) {
-      // TODO necessary??
-      checkState(totalMap == null, "Hazard has already been added to this builder");
+        componentMaps = new EnumMap<>(Imt.class);
+        totalMap = new EnumMap<>(Imt.class);
 
-      componentMaps = new EnumMap<>(Imt.class);
-      totalMap = new EnumMap<>(Imt.class);
+        var typeTotalMaps = curvesBySource(hazard);
 
-      var typeTotalMaps = curvesBySource(hazard);
+        for (var imt : hazard.curves().keySet()) {
 
-      for (var imt : hazard.curves().keySet()) {
+          /* Total curve for IMT. */
+          XySequence.addToMap(imt, totalMap, hazard.curves().get(imt));
 
-        /* Total curve for IMT. */
-        XySequence.addToMap(imt, totalMap, hazard.curves().get(imt));
+          /* Source component curves for IMT. */
+          var typeTotalMap = typeTotalMaps.get(imt);
+          var componentMap = componentMaps.get(imt);
 
-        /* Source component curves for IMT. */
-        var typeTotalMap = typeTotalMaps.get(imt);
-        var componentMap = componentMaps.get(imt);
+          if (componentMap == null) {
+            componentMap = new EnumMap<>(SourceType.class);
+            componentMaps.put(imt, componentMap);
+          }
 
-        if (componentMap == null) {
-          componentMap = new EnumMap<>(SourceType.class);
-          componentMaps.put(imt, componentMap);
+          for (var type : typeTotalMap.keySet()) {
+            XySequence.addToMap(type, componentMap, typeTotalMap.get(type));
+          }
         }
 
-        for (var type : typeTotalMap.keySet()) {
-          XySequence.addToMap(type, componentMap, typeTotalMap.get(type));
-        }
+        return this;
       }
 
-      return this;
-    }
-
-    Response build() {
-      var hazards = new ArrayList<ImtCurves>();
-
-      for (Imt imt : totalMap.keySet()) {
-        var curves = new ArrayList<Curve>();
+      Response build() {
+        var hazards = new ArrayList<ImtCurves>();
 
-        // total curve
-        curves.add(new Curve(
-            TOTAL_KEY,
-            updateCurve(request, totalMap.get(imt), imt)));
+        for (Imt imt : totalMap.keySet()) {
+          var curves = new ArrayList<Curve>();
 
-        // component curves
-        var typeMap = componentMaps.get(imt);
-        for (SourceType type : typeMap.keySet()) {
+          // total curve
           curves.add(new Curve(
-              type.toString(),
-              updateCurve(request, typeMap.get(type), imt)));
+              TOTAL_KEY,
+              updateCurve(request, totalMap.get(imt), imt)));
+
+          // component curves
+          var typeMap = componentMaps.get(imt);
+          for (SourceType type : typeMap.keySet()) {
+            curves.add(new Curve(
+                type.toString(),
+                updateCurve(request, typeMap.get(type), imt)));
+          }
+
+          hazards.add(new ImtCurves(imt, curves));
         }
 
-        hazards.add(new ImtCurves(imt, curves));
+        Object server = ServletUtil.serverData(ServletUtil.THREAD_COUNT, timer);
+        var response = new Response(
+            new Response.Metadata(server),
+            hazards);
+
+        return response;
       }
+    }
+
+  }
+
+  private static final class ImtCurves {
+    final Parameter imt;
+    final List<Curve> data;
+
+    ImtCurves(Imt imt, List<Curve> data) {
+      this.imt = new Parameter(ServletUtil.imtShortLabel(imt), imt.name());
+      this.data = data;
+    }
+  }
 
-      Object server = Metadata.serverData(ServletUtil.THREAD_COUNT, timer);
-      var response = new Response(
-          new ResponseMetadata(server),
-          hazards);
+  private static final class Curve {
+    final String component;
+    final XySequence values;
 
-      return response;
+    Curve(String component, XySequence values) {
+      this.component = component;
+      this.values = values;
     }
   }
 
@@ -353,5 +354,4 @@ public final class HazardService {
         .map(Imt::valueOf)
         .collect(toCollection(() -> EnumSet.noneOf(Imt.class)));
   }
-
 }
diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/meta/Metadata.java b/src/main/java/gov/usgs/earthquake/nshmp/www/meta/Metadata.java
index ed8a2973d0cb7ce54e00d8d68d35dd70c4260c51..84227bdce0090294ed736dc7c52b3ecb55bd7e90 100644
--- a/src/main/java/gov/usgs/earthquake/nshmp/www/meta/Metadata.java
+++ b/src/main/java/gov/usgs/earthquake/nshmp/www/meta/Metadata.java
@@ -28,43 +28,11 @@ public final class Metadata {
       this.status = Status.USAGE.toString();
       this.description = description;
       this.syntax = syntax;
-      this.server = serverData(1, Stopwatch.createStarted());
+      this.server = ServletUtil.serverData(1, Stopwatch.createStarted());
       this.parameters = parameters;
     }
   }
 
-  public static Object serverData(int threads, Stopwatch timer) {
-    return new Server(threads, timer);
-  }
-
-  private static class Server {
-
-    final int threads;
-    final String timer;
-    final String version;
-
-    Server(int threads, Stopwatch timer) {
-      this.threads = threads;
-      this.timer = timer.toString();
-      this.version = "TODO where to get version?";
-    }
-
-    // static Component NSHMP_HAZ_COMPONENT = new Component(
-    // NSHMP_HAZ_URL,
-    // Versions.NSHMP_HAZ_VERSION);
-    //
-    // static final class Component {
-    //
-    // final String url;
-    // final String version;
-    //
-    // Component(String url, String version) {
-    // this.url = url;
-    // this.version = version;
-    // }
-    // }
-  }
-
   public static class DefaultParameters {
 
     // final EnumParameter<Edition> edition;
diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/services/RateService.java b/src/main/java/gov/usgs/earthquake/nshmp/www/services/RateService.java
index 6b042038acae6b44f8b6253f5c68ace9fe4a38b5..05f2389c6fceaeb1927de91ff90542edc279d98c 100644
--- a/src/main/java/gov/usgs/earthquake/nshmp/www/services/RateService.java
+++ b/src/main/java/gov/usgs/earthquake/nshmp/www/services/RateService.java
@@ -26,7 +26,6 @@ import gov.usgs.earthquake.nshmp.www.ServicesUtil.ServiceRequestData;
 import gov.usgs.earthquake.nshmp.www.ServletUtil;
 import gov.usgs.earthquake.nshmp.www.WsUtils;
 import gov.usgs.earthquake.nshmp.www.meta.DoubleParameter;
-import gov.usgs.earthquake.nshmp.www.meta.Metadata;
 import gov.usgs.earthquake.nshmp.www.meta.Metadata.DefaultParameters;
 import io.micronaut.http.HttpRequest;
 import io.micronaut.http.HttpResponse;
@@ -276,7 +275,7 @@ public final class RateService {
     final List<Sequence> data;
 
     ResponseData(ResponseMetadata metadata, EqRate rates, Stopwatch timer) {
-      server = Metadata.serverData(ServletUtil.THREAD_COUNT, timer);
+      server = ServletUtil.serverData(ServletUtil.THREAD_COUNT, timer);
       this.metadata = metadata;
       this.data = buildSequence(rates);
     }
@@ -335,7 +334,7 @@ public final class RateService {
     private Usage(Service service, DefaultParameters parameters) {
       description = service.description;
       this.syntax = service.syntax;
-      server = Metadata.serverData(1, Stopwatch.createStarted());
+      server = ServletUtil.serverData(1, Stopwatch.createStarted());
       this.parameters = parameters;
     }
   }
diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/services/SourceServices.java b/src/main/java/gov/usgs/earthquake/nshmp/www/services/SourceServices.java
index 75cf76b285f57e1fb6f489d63088c7c310f9ac28..f55efc1d74ba8e5c1ea08d7ff41a5177cc302b0b 100644
--- a/src/main/java/gov/usgs/earthquake/nshmp/www/services/SourceServices.java
+++ b/src/main/java/gov/usgs/earthquake/nshmp/www/services/SourceServices.java
@@ -20,7 +20,6 @@ import gov.usgs.earthquake.nshmp.model.HazardModel;
 import gov.usgs.earthquake.nshmp.www.ResponseBody;
 import gov.usgs.earthquake.nshmp.www.ServletUtil;
 import gov.usgs.earthquake.nshmp.www.WsUtils;
-import gov.usgs.earthquake.nshmp.www.meta.Metadata;
 import gov.usgs.earthquake.nshmp.www.meta.Parameter;
 import io.micronaut.http.HttpRequest;
 import io.micronaut.http.HttpResponse;
@@ -80,7 +79,9 @@ public class SourceServices {
 
     public ResponseData() {
       this.description = "Installed source model listing";
-      this.server = Metadata.serverData(ServletUtil.THREAD_COUNT, Stopwatch.createStarted());
+      this.server = ServletUtil.serverData(
+          ServletUtil.THREAD_COUNT,
+          Stopwatch.createStarted());
       // this.parameters = new Parameters();
     }
   }
@@ -122,6 +123,7 @@ public class SourceServices {
       imts = model.gmms().stream()
           .map(Gmm::supportedImts)
           .flatMap(Set::stream)
+          .distinct()
           .sorted()
           .map(imt -> new Parameter(ServletUtil.imtShortLabel(imt), imt.name()))
           .collect(toList());