@Nullable
  public static ExternalSystemEvent deserialize(@NotNull String line, int version) {
    int payloadStartIndex = version == 0 ? 2 : 3;
    String[] parts = line.split(" ");
    int length = parts.length;
    if (length < payloadStartIndex) {
      return null;
    }

    ExternalSystemEventType type = ExternalSystemEventType.parse(parts[1]);
    if (type == null) {
      return null;
    }

    long timestamp = parseLong(parts[0]);
    String recorderId = version == 0 ? "FUS" : parts[2];
    if (type == ExternalSystemEventType.FINISHED) {
      String error = length > payloadStartIndex ? parts[payloadStartIndex].trim() : null;
      return new ExternalUploadFinishedEvent(timestamp, error, recorderId);
    }
    else if (type == ExternalSystemEventType.SEND && length > payloadStartIndex + 2) {
      int succeed = parseInt(parts[payloadStartIndex]);
      int failed = parseInt(parts[payloadStartIndex + 1]);
      int total = parseInt(parts[payloadStartIndex + 2]);
      List<String> sentFiles = length > payloadStartIndex + 3 ? parseSentFiles(parts[payloadStartIndex + 3]) : Collections.emptyList();
      List<Integer> errors = length > payloadStartIndex + 4 ? parseErrors(parts[payloadStartIndex + 4]) : Collections.emptyList();
      return new ExternalUploadSendEvent(timestamp, succeed, failed, total, sentFiles, errors, recorderId);
    }
    else if (type == ExternalSystemEventType.STARTED && length == payloadStartIndex) {
      return new ExternalUploadStartedEvent(timestamp, recorderId);
    }
    else if (type == ExternalSystemEventType.ERROR && length == payloadStartIndex + 2) {
      String event = parts[payloadStartIndex].trim();
      String errorClass = parts[payloadStartIndex + 1].trim();
      return new ExternalSystemErrorEvent(timestamp, event, errorClass, recorderId);
    }
    return null;
  }
@Nullable
  public static ExternalSystemEvent deserialize(@NotNull String line, int version)