static String writeConfig(ZipkinUiProperties ui) throws IOException {
    StringWriter writer = new StringWriter();
    try (JsonGenerator generator = JsonUtil.createGenerator(writer)) {
      generator.useDefaultPrettyPrinter();
      generator.writeStartObject();
      generator.writeStringField("environment", ui.getEnvironment());
      generator.writeNumberField("queryLimit", ui.getQueryLimit());
      generator.writeNumberField("defaultLookback", ui.getDefaultLookback());
      generator.writeBooleanField("searchEnabled", ui.isSearchEnabled());
      generator.writeStringField("logsUrl", ui.getLogsUrl());
      generator.writeStringField("supportUrl", ui.getSupportUrl());
      generator.writeStringField("archivePostUrl", ui.getArchivePostUrl());
      generator.writeStringField("archiveUrl", ui.getArchiveUrl());
      generator.writeObjectFieldStart("dependency");
      generator.writeBooleanField("enabled", ui.getDependency().isEnabled());
      generator.writeNumberField("lowErrorRate", ui.getDependency().getLowErrorRate());
      generator.writeNumberField("highErrorRate", ui.getDependency().getHighErrorRate());
      generator.writeEndObject(); // .dependency
      generator.writeEndObject(); // .
    }
    return writer.toString();
  }
Zipkin-UI is a single-page application mounted at /zipkin. For simplicity, assume paths mentioned
below are relative to that. For example, the UI reads config.json, from the absolute path
/zipkin/config.json

<p>When looking at a trace, the browser is sent to the path "/traces/{id}". For the single-page
app to serve that route, the server needs to forward the request to "/index.html". The same
forwarding applies to "/dependencies" and any other routes the UI controls.

<p>Under the scenes the JavaScript code looks at {@code window.location} to figure out what the
UI should do. This is handled by a route api defined in the crossroads library.

<h3>Caching</h3>
<p>This includes a hard-coded cache policy, consistent with zipkin-scala.
<ul>
  <li>1 minute for index.html</li>
  <li>10 minute for /config.json</li>
  <li>365 days for hashed resources (ex /app-e12b3bbb7e5a572f270d.min.js)</li>
</ul>
Since index.html links to hashed resource names, any change to it will orphan old resources.
That's why hashed resource age can be 365 days.
zipkin-server/src/main/java/zipkin2/server/internal/ui/ZipkinUiConfiguration.java