docs: public static void main(String[] args) {
      BasicConfigurator.configure(new ConsoleAppender(
              new PatternLayout("%-5p: %m%n")));
  
      CmdLineParser parser = new CmdLineParser();
      CmdLineParser.Option help = parser.addBooleanOption('h', "help");
      CmdLineParser.Option filename = parser.addStringOption('t', "torrent");
      CmdLineParser.Option create = parser.addBooleanOption('c', "create");
      CmdLineParser.Option pieceLength = parser.addIntegerOption('l', "length");
      CmdLineParser.Option announce = parser.addStringOption('a', "announce");
  
      try {
        parser.parse(args);
      } catch (CmdLineParser.OptionException oe) {
        System.err.println(oe.getMessage());
        usage(System.err);
        System.exit(1);
      }
  
      // Display help and exit if requested
      if (Boolean.TRUE.equals(parser.getOptionValue(help))) {
        usage(System.out);
        System.exit(0);
      }
  
      String filenameValue = (String) parser.getOptionValue(filename);
      if (filenameValue == null) {
        usage(System.err, "Torrent file must be provided!");
        System.exit(1);
      }
  
      Integer pieceLengthVal = (Integer) parser.getOptionValue(pieceLength);
      if (pieceLengthVal == null) {
        pieceLengthVal = TorrentCreator.DEFAULT_PIECE_LENGTH;
      } else {
        pieceLengthVal = pieceLengthVal * 1024;
      }
      logger.info("Using piece length of {} bytes.", pieceLengthVal);
  
      Boolean createFlag = (Boolean) parser.getOptionValue(create);
  
      //For repeated announce urls
      @SuppressWarnings("unchecked")
      Vector<String> announceURLs = (Vector<String>) parser.getOptionValues(announce);
  
      String[] otherArgs = parser.getRemainingArgs();
  
      if (Boolean.TRUE.equals(createFlag) &&
              (otherArgs.length != 1 || announceURLs.isEmpty())) {
        usage(System.err, "Announce URL and a file or directory must be " +
                "provided to create a torrent file!");
        System.exit(1);
      }
  
      OutputStream fos = null;
      try {
        if (Boolean.TRUE.equals(createFlag)) {
          fos = new FileOutputStream(filenameValue);
  
          //Process the announce URLs into URIs
          List<URI> announceURIs = new ArrayList<URI>();
          for (String url : announceURLs) {
            announceURIs.add(new URI(url));
          }
  
          //Create the announce-list as a list of lists of URIs
          //Assume all the URI's are first tier trackers
          List<List<URI>> announceList = new ArrayList<List<URI>>();
          announceList.add(announceURIs);
  
          File source = new File(otherArgs[0]);
          if (!source.exists() || !source.canRead()) {
            throw new IllegalArgumentException(
                    "Cannot access source file or directory " +
                            source.getName());
          }
  
          String creator = String.format("%s (ttorrent)",
                  System.getProperty("user.name"));
  
          TorrentMetadata torrent;
          if (source.isDirectory()) {
            List<File> files = new ArrayList<File>(FileUtils.listFiles(source, TrueFileFilter.TRUE, TrueFileFilter.TRUE));
            Collections.sort(files);
            torrent = TorrentCreator.create(source, files, announceList.get(0).get(0), announceList, creator, pieceLengthVal);
          } else {
            torrent = TorrentCreator.create(source, null, announceList.get(0).get(0), announceList, creator, pieceLengthVal);
          }
  
          fos.write(new TorrentSerializer().serialize(torrent));
        } else {
          new TorrentParser().parseFromFile(new File(filenameValue));
        }
      } catch (Exception e) {
        logger.error("{}", e.getMessage(), e);
        System.exit(2);
      } finally {
        if (fos != System.out) {
          IOUtils.closeQuietly(fos);
        }
      }
    }