docs: @SuppressWarnings("resource")
    public static void main(String[] allArgs) {
      int exitStatus = 0;
  
      Serializer serializer = null;
      try {
        final ArrayDeque<String> args = new ArrayDeque<String>(Arrays.asList(allArgs));
  
        // Options.
        boolean debugStream = false;
        boolean flushFrequently = false;
        File  eventsFile = null;
        boolean suitesOnStdin = false;
        List<String> testClasses = new ArrayList<>();
        String runListeners = null;
  
        while (!args.isEmpty()) {
          String option = args.pop();
          if (option.equals(OPTION_FREQUENT_FLUSH)) {
            flushFrequently = true;
          } else if (option.equals(OPTION_STDIN)) {
            suitesOnStdin = true;
          } else if (option.equals(OPTION_SYSOUTS)) {
            multiplexStdStreams = true;
          } else if (option.equals(OPTION_EVENTSFILE)) {
            eventsFile = new File(args.pop());
            if (eventsFile.isFile() && eventsFile.length() > 0) {
              RandomAccessFile raf = new RandomAccessFile(eventsFile, "rw");
              raf.setLength(0);
              raf.close();
            }
          } else if (option.equals(OPTION_RUN_LISTENERS)) {
            runListeners = args.pop();
          } else if (option.startsWith(OPTION_DEBUGSTREAM)) {
            debugStream = true;
          } else if (option.startsWith("@")) {
            // Append arguments file, one line per option.
            args.addAll(Arrays.asList(readArgsFile(option.substring(1))));
          } else {
            // The default expectation is a test class.
            testClasses.add(option);
          }
        }
  
        // Set up events channel and events serializer.
        if (eventsFile == null) {
          throw new IOException("You must specify communication channel for events.");
        }
  
        // Delay the forked JVM a bit (for tests).
        if (System.getProperty(SYSPROP_FORKEDJVM_DELAY_MS) != null) {
          Thread.sleep(Integer.parseInt(System.getProperty(SYSPROP_FORKEDJVM_DELAY_MS)));
        }
        
        // Send bootstrap package.
        serializer = new Serializer(new EventsOutputStream(eventsFile))
          .serialize(new BootstrapEvent())
          .flush();
  
        // Redirect original streams and start running tests.
        redirectStreams(serializer, flushFrequently);
  
        final SlaveMain main = new SlaveMain(serializer);
        main.flushFrequently = flushFrequently;
        main.debugMessagesFile = debugStream ? new File(eventsFile.getAbsolutePath() + ".debug"): null;
        main.runListeners = runListeners;
  
        final Iterator<String> stdInput;
        if (suitesOnStdin) { 
          stdInput = new StdInLineIterator(main.serializer);
        } else {
          stdInput = Collections.<String>emptyList().iterator();
        }
  
        main.execute(Iterators.concat(testClasses.iterator(), stdInput));
        
        // For unhandled exceptions tests.
        if (System.getProperty(SYSPROP_FIRERUNNERFAILURE) != null) {
          throw new Exception(System.getProperty(SYSPROP_FIRERUNNERFAILURE));
        }
      } catch (Throwable t) {
        lastResortMemory = null;
        tryWaitingForGC();
  
        if (t.getClass() == oomClass) {
          exitStatus = ERR_OOM;
          warn("JVM out of memory.", t);
        } else {
          exitStatus = ERR_EXCEPTION;
          warn("Exception at main loop level.", t);
        }
      }
  
      try {
        if (serializer != null) {
          try {
            serializer.close();
          } catch (Throwable t) {
            warn("Exception closing serializer.", t);
          }
        }
      } finally {
        JvmExit.halt(exitStatus);
      }
    }