void parse(Span in) {
      endTs = msTs = wsTs = wrTs = mrTs = 0L;
      begin = end = addr = null;

      startTs = in.timestampAsLong();
      endTs = startTs != 0L && in.durationAsLong() != 0L ? startTs + in.durationAsLong() : 0L;

      Span.Kind kind = in.kind();

      // scan annotations in case there are better timestamps, or inferred kind
      for (int i = 0, length = in.annotations().size(); i < length; i++) {
        Annotation a = in.annotations().get(i);
        String value = a.value();
        if (value.length() != 2) continue;

        if (value.equals("cs")) {
          kind = Span.Kind.CLIENT;
          if (a.timestamp() < startTs) startTs = a.timestamp();
        } else if (value.equals("sr")) {
          kind = Span.Kind.SERVER;
          if (a.timestamp() < startTs) startTs = a.timestamp();
        } else if (value.equals("ss")) {
          kind = Span.Kind.SERVER;
          if (a.timestamp() > endTs) endTs = a.timestamp();
        } else if (value.equals("cr")) {
          kind = Span.Kind.CLIENT;
          if (a.timestamp() > endTs) endTs = a.timestamp();
        } else if (value.equals("ms")) {
          kind = Span.Kind.PRODUCER;
          msTs = a.timestamp();
        } else if (value.equals("mr")) {
          kind = Span.Kind.CONSUMER;
          mrTs = a.timestamp();
        } else if (value.equals("ws")) {
          wsTs = a.timestamp();
        } else if (value.equals("wr")) {
          wrTs = a.timestamp();
        }
      }

      if (in.remoteEndpoint() != null) addr = "sa"; // default value

      if (kind == null) return;

      switch (kind) {
        case CLIENT:
          addr = "sa";
          begin = "cs";
          end = "cr";
          break;
        case SERVER:
          addr = "ca";
          begin = "sr";
          end = "ss";
          break;
        case PRODUCER:
          addr = "ma";
          begin = "ms";
          end = "ws";
          if (startTs == 0L || (msTs != 0 && msTs < startTs)) {
            startTs = msTs;
          }
          if (endTs == 0L || (wsTs != 0 && wsTs > endTs)) {
            endTs = wsTs;
          }
          break;
        case CONSUMER:
          addr = "ma";
          if (startTs == 0L || (wrTs != 0 && wrTs < startTs)) {
            startTs = wrTs;
          }
          if (endTs == 0L || (mrTs != 0 && mrTs > endTs)) {
            endTs = mrTs;
          }
          if (endTs != 0L || wrTs != 0) {
            begin = "wr";
            end = "mr";
          } else {
            begin = "mr";
          }
          break;
        default:
          throw new AssertionError("update kind mapping");
      }

      // If we didn't find a span kind, directly or indirectly, unset the addr
      if (in.remoteEndpoint() == null) addr = null;
    }
Allows you convert a v2 span into a v1 span. This is helpful for legacy storage which still use
annotations. This shouldn't be used by new code.

<p>This type isn't thread-safe: it re-uses state to avoid re-allocations in conversion loops.
zipkin/src/main/java/zipkin2/v1/V2SpanConverter.java