code: public static Process buildProcess(String[] commandLine,
                                         @Nullable Reader input,
                                         @Nullable Consumer<String> stdOutConsumer,
                                         @Nullable Consumer<String> stdErrConsumer) throws IOException {
  
          final ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
          final Process process = processBuilder.start();
  
          writeProcessInput(process, input);
  
          if (stdOutConsumer != null) {
              final Thread stdOutThread =
                      new StreamGobbler(process.getInputStream(), new DelegatingConsumer(stdOutConsumer));
              stdOutThread.start();
          }
  
          if (stdErrConsumer != null) {
              final Thread stdErrThread =
                      new StreamGobbler(process.getErrorStream(), new DelegatingConsumer(stdErrConsumer));
              stdErrThread.start();
          }
  
          return process;
      }
docs: Builds and starts a system process for the given set of command line arguments. Additionally allows to supply an
  input stream to the invoked program, as well as independent consumers for the process' standard and error output.
  <p>
  The consumers for the process' outputs run in separate threads, preventing potential deadlock scenarios where
  client code waits for the process' termination (e.g. {@link Process#waitFor()}) which is blocked by full system
  buffers.
  
  @param commandLine
  the list of command line arguments to run
  @param input
  the input passed to the program, maybe be {@code null} if the process expects no input
  @param stdOutConsumer
  the consumer for the programs output
  @param stdErrConsumer
  the consumer for the programs output
  
  @return the reference to the running process
  
  @throws IOException
  if an exception occurred while reading the process outputs