code: private TestSuiteModel buildModel(AggregatedSuiteResultEvent e) throws IOException {
      SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ROOT);
      TestSuiteModel suite = new TestSuiteModel();
  
      suite.hostname = "nohost.nodomain";
      suite.name = e.getDescription().getDisplayName();
      suite.properties = buildModel(e.getSlave().getSystemProperties());
      suite.time = e.getExecutionTime() / 1000.0;
      suite.timestamp = df.format(new Date(e.getStartTimestamp()));
  
      suite.testcases = buildModel(e.getTests());
      suite.tests = suite.testcases.size();
  
      if (mavenExtensions) {
        suite.skipped = 0;
      }
  
      // Suite-level failures and errors are simulated as test cases.
      for (FailureMirror m : e.getFailures()) {
        TestCaseModel model = new TestCaseModel();
        model.classname = "junit.framework.TestSuite"; // empirical ANT output.
        model.name = applyFilters(m.getDescription().getClassName());
        model.time = 0;
        if (m.isAssertionViolation()) {
          model.failures.add(buildModel(m));
        } else {
          model.errors.add(buildModel(m));
        }
        suite.testcases.add(model);
      }
  
      // Calculate test numbers that match limited view (no ignored tests, 
      // faked suite-level errors).
      for (TestCaseModel tc : suite.testcases) {
        suite.errors += tc.errors.size();
        suite.failures += tc.failures.size();
        if (mavenExtensions && tc.skipped != null) {
          suite.skipped += 1;
        }
      }
  
      StringWriter sysout = new StringWriter();
      StringWriter syserr = new StringWriter();
      if (outputStreams) {
        e.getSlave().decodeStreams(e.getEventStream(), sysout, syserr);
      }
      suite.sysout = sysout.toString();
      suite.syserr = syserr.toString();
  
      return suite;
    }
docs: Build data model for serialization.