- * [CUSTOMLEVEL2=WEIGHT2 [CUSTOMLEVEL3=WEIGHT3] ...]}
- * 
- * Example of creating an extended logger:
- * To generate source code for a custom logger that replaces the existing log levels with custom ones:  =
- * [CUSTOMLEVEL2=WEIGHT2 [CUSTOMLEVEL3=WEIGHT3] ...]}
- * 
- * Example of creating a custom logger:
Compatible with Log4j 2.6 or higher.
%n"
-                        + " */%n"
-                        + "public final class %s {%n"
-                        + "    private final ExtendedLoggerWrapper logger;%n"
-                        + "%n";
-                // @formatter:on
-            }
-
-            @Override
-            String constructor() {
-                // @formatter:off
-                return ""
-                        + "%n"
-                        + "    private %s(final Logger logger) {%n"
-                        + "        this.logger = new ExtendedLoggerWrapper((ExtendedLogger) logger, logger.getName(), "
-                        + "logger.getMessageFactory());%n"
-                        + "    }%n";
-                // @formatter:on
-            }
-
-            @Override
-            Class> generator() {
-                return CustomLogger.class;
-            }
-        },
-        EXTEND {
-            @Override
-            String imports() {
-                // @formatter:off
-                return ""
-                        + "import org.apache.logging.log4j.Level;%n"
-                        + "import org.apache.logging.log4j.LogManager;%n"
-                        + "import org.apache.logging.log4j.Logger;%n"
-                        + "import org.apache.logging.log4j.Marker;%n"
-                        + "import org.apache.logging.log4j.message.Message;%n"
-                        + "import org.apache.logging.log4j.message.MessageFactory;%n"
-                        + "import org.apache.logging.log4j.spi.ExtendedLogger;%n"
-                        + "import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;%n"
-                        + "import org.apache.logging.log4j.util.MessageSupplier;%n"
-                        + "import org.apache.logging.log4j.util.Supplier;%n"
-                        + "%n";
-                // @formatter:on
-            }
-
-            @Override
-            String declaration() {
-                // @formatter:off
-                return ""
-                        + "/**%n"
-                        + " * Extended Logger interface with convenience methods for%n"
-                        + " * %s%n"
-                        + " * Compatible with Log4j 2.6 or higher.
%n"
-                        + " */%n"
-                        + "public final class %s extends ExtendedLoggerWrapper {%n"
-                        + "    private static final long serialVersionUID = " + System.nanoTime() + "L;%n"
-                        + "    private final ExtendedLoggerWrapper logger;%n"
-                        + "%n";
-                // @formatter:on
-            }
-
-            @Override
-            String constructor() {
-                // @formatter:off
-                return ""
-                        + "%n"
-                        + "    private %s(final Logger logger) {%n"
-                        + "        super((ExtendedLogger) logger, logger.getName(), logger.getMessageFactory());%n"
-                        + "        this.logger = this;%n"
-                        + "    }%n";
-                // @formatter:on
-            }
-
-            @Override
-            Class> generator() {
-                return ExtendedLogger.class;
-            }
-        };
-
-        abstract String imports();
-
-        abstract String declaration();
-
-        abstract String constructor();
-
-        abstract Class> generator();
-    }
-
-    static final String FQCN_FIELD = "" + "    private static final String FQCN = %s.class.getName();%n";
-
-    static final String LEVEL_FIELD = "" + "    private static final Level %s = Level.forName(\"%s\", %d);%n";
-
-    static final String FACTORY_METHODS = ""
-            // @formatter:off
-            + "%n"
-            + "    /**%n"
-            + "     * Returns a custom Logger with the name of the calling class.%n"
-            + "     * %n"
-            + "     * @return The custom Logger for the calling class.%n"
-            + "     */%n"
-            + "    public static CLASSNAME create() {%n"
-            + "        final Logger wrapped = LogManager.getLogger();%n"
-            + "        return new CLASSNAME(wrapped);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Returns a custom Logger using the fully qualified name of the Class as%n"
-            + "     * the Logger name.%n"
-            + "     * %n"
-            + "     * @param loggerName The Class whose name should be used as the Logger name.%n"
-            + "     *            If null it will default to the calling class.%n"
-            + "     * @return The custom Logger.%n"
-            + "     */%n"
-            + "    public static CLASSNAME create(final Class> loggerName) {%n"
-            + "        final Logger wrapped = LogManager.getLogger(loggerName);%n"
-            + "        return new CLASSNAME(wrapped);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Returns a custom Logger using the fully qualified name of the Class as%n"
-            + "     * the Logger name.%n"
-            + "     * %n"
-            + "     * @param loggerName The Class whose name should be used as the Logger name.%n"
-            + "     *            If null it will default to the calling class.%n"
-            + "     * @param messageFactory The message factory is used only when creating a%n"
-            + "     *            logger, subsequent use does not change the logger but will log%n"
-            + "     *            a warning if mismatched.%n"
-            + "     * @return The custom Logger.%n"
-            + "     */%n"
-            + "    public static CLASSNAME create(final Class> loggerName, final MessageFactory"
-            + " messageFactory) {%n"
-            + "        final Logger wrapped = LogManager.getLogger(loggerName, messageFactory);%n"
-            + "        return new CLASSNAME(wrapped);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Returns a custom Logger using the fully qualified class name of the value%n"
-            + "     * as the Logger name.%n"
-            + "     * %n"
-            + "     * @param value The value whose class name should be used as the Logger%n"
-            + "     *            name. If null the name of the calling class will be used as%n"
-            + "     *            the logger name.%n"
-            + "     * @return The custom Logger.%n"
-            + "     */%n"
-            + "    public static CLASSNAME create(final Object value) {%n"
-            + "        final Logger wrapped = LogManager.getLogger(value);%n"
-            + "        return new CLASSNAME(wrapped);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Returns a custom Logger using the fully qualified class name of the value%n"
-            + "     * as the Logger name.%n"
-            + "     * %n"
-            + "     * @param value The value whose class name should be used as the Logger%n"
-            + "     *            name. If null the name of the calling class will be used as%n"
-            + "     *            the logger name.%n"
-            + "     * @param messageFactory The message factory is used only when creating a%n"
-            + "     *            logger, subsequent use does not change the logger but will log%n"
-            + "     *            a warning if mismatched.%n"
-            + "     * @return The custom Logger.%n"
-            + "     */%n"
-            + "    public static CLASSNAME create(final Object value, final MessageFactory messageFactory) {%n"
-            + "        final Logger wrapped = LogManager.getLogger(value, messageFactory);%n"
-            + "        return new CLASSNAME(wrapped);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Returns a custom Logger with the specified name.%n"
-            + "     * %n"
-            + "     * @param name The logger name. If null the name of the calling class will%n"
-            + "     *            be used.%n"
-            + "     * @return The custom Logger.%n"
-            + "     */%n"
-            + "    public static CLASSNAME create(final String name) {%n"
-            + "        final Logger wrapped = LogManager.getLogger(name);%n"
-            + "        return new CLASSNAME(wrapped);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Returns a custom Logger with the specified name.%n"
-            + "     * %n"
-            + "     * @param name The logger name. If null the name of the calling class will%n"
-            + "     *            be used.%n"
-            + "     * @param messageFactory The message factory is used only when creating a%n"
-            + "     *            logger, subsequent use does not change the logger but will log%n"
-            + "     *            a warning if mismatched.%n"
-            + "     * @return The custom Logger.%n"
-            + "     */%n"
-            + "    public static CLASSNAME create(final String name, final MessageFactory messageFactory) {%n"
-            + "        final Logger wrapped = LogManager.getLogger(name, messageFactory);%n"
-            + "        return new CLASSNAME(wrapped);%n"
-            + "    }%n";
-    // @formatter:on
-
-    static final String METHODS = ""
-            // @formatter:off
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with the specific Marker at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param msg the message string to be logged%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final Message msg) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msg, (Throwable) null);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with the specific Marker at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param msg the message string to be logged%n"
-            + "     * @param t A Throwable or null.%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final Message msg, final Throwable t) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msg, t);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message object with the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message object to log.%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final Object message) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, (Throwable) null);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message CharSequence with the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message CharSequence to log.%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final CharSequence message) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, (Throwable) null);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message at the {@code CUSTOM_LEVEL} level including the stack trace of%n"
-            + "     * the {@link Throwable} {@code t} passed as parameter.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message to log.%n"
-            + "     * @param t the exception to log, including its stack trace.%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final Object message, final Throwable t) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, t);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message at the {@code CUSTOM_LEVEL} level including the stack trace of%n"
-            + "     * the {@link Throwable} {@code t} passed as parameter.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the CharSequence to log.%n"
-            + "     * @param t the exception to log, including its stack trace.%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final CharSequence message, final Throwable t) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, t);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message object with the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message object to log.%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final String message) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, (Throwable) null);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param params parameters to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final String message, final Object... params) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, params);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final String message, final Object p0) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, p0);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final String message, final Object p0, "
-            + "final Object p1) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, p0, p1);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final String message, final Object p0, "
-            + "final Object p1, final Object p2) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, p0, p1, p2);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @param p3 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final String message, final Object p0, "
-            + "final Object p1, final Object p2,%n"
-            + "            final Object p3) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, p0, p1, p2, p3);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @param p3 parameter to the message.%n"
-            + "     * @param p4 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final String message, final Object p0, "
-            + "final Object p1, final Object p2,%n"
-            + "            final Object p3, final Object p4) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, p0, p1, p2, p3, p4);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @param p3 parameter to the message.%n"
-            + "     * @param p4 parameter to the message.%n"
-            + "     * @param p5 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final String message, final Object p0, "
-            + "final Object p1, final Object p2,%n"
-            + "            final Object p3, final Object p4, final Object p5) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, p0, p1, p2, p3, p4, p5);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @param p3 parameter to the message.%n"
-            + "     * @param p4 parameter to the message.%n"
-            + "     * @param p5 parameter to the message.%n"
-            + "     * @param p6 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final String message, final Object p0, "
-            + "final Object p1, final Object p2,%n"
-            + "            final Object p3, final Object p4, final Object p5, final Object p6) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, p0, p1, p2, p3, p4, p5, p6);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @param p3 parameter to the message.%n"
-            + "     * @param p4 parameter to the message.%n"
-            + "     * @param p5 parameter to the message.%n"
-            + "     * @param p6 parameter to the message.%n"
-            + "     * @param p7 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final String message, final Object p0, "
-            + "final Object p1, final Object p2,%n"
-            + "            final Object p3, final Object p4, final Object p5, final Object p6,%n"
-            + "            final Object p7) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, p0, p1, p2, p3, p4, p5, p6, p7);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @param p3 parameter to the message.%n"
-            + "     * @param p4 parameter to the message.%n"
-            + "     * @param p5 parameter to the message.%n"
-            + "     * @param p6 parameter to the message.%n"
-            + "     * @param p7 parameter to the message.%n"
-            + "     * @param p8 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final String message, final Object p0, "
-            + "final Object p1, final Object p2,%n"
-            + "            final Object p3, final Object p4, final Object p5, final Object p6,%n"
-            + "            final Object p7, final Object p8) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, p0, p1, p2, p3, p4, p5, p6, p7, "
-            + "p8);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @param p3 parameter to the message.%n"
-            + "     * @param p4 parameter to the message.%n"
-            + "     * @param p5 parameter to the message.%n"
-            + "     * @param p6 parameter to the message.%n"
-            + "     * @param p7 parameter to the message.%n"
-            + "     * @param p8 parameter to the message.%n"
-            + "     * @param p9 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final String message, final Object p0, "
-            + "final Object p1, final Object p2,%n"
-            + "            final Object p3, final Object p4, final Object p5, final Object p6,%n"
-            + "            final Object p7, final Object p8, final Object p9) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, p0, p1, p2, p3, p4, p5, p6, p7, "
-            + "p8, p9);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message at the {@code CUSTOM_LEVEL} level including the stack trace of%n"
-            + "     * the {@link Throwable} {@code t} passed as parameter.%n"
-            + "     * %n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message to log.%n"
-            + "     * @param t the exception to log, including its stack trace.%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final String message, final Throwable t) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, t);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs the specified Message at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param msg the message string to be logged%n"
-            + "     */%n"
-            + "    public void methodName(final Message msg) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msg, (Throwable) null);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs the specified Message at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param msg the message string to be logged%n"
-            + "     * @param t A Throwable or null.%n"
-            + "     */%n"
-            + "    public void methodName(final Message msg, final Throwable t) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msg, t);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message object with the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param message the message object to log.%n"
-            + "     */%n"
-            + "    public void methodName(final Object message) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, (Throwable) null);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message at the {@code CUSTOM_LEVEL} level including the stack trace of%n"
-            + "     * the {@link Throwable} {@code t} passed as parameter.%n"
-            + "     * %n"
-            + "     * @param message the message to log.%n"
-            + "     * @param t the exception to log, including its stack trace.%n"
-            + "     */%n"
-            + "    public void methodName(final Object message, final Throwable t) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, t);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message CharSequence with the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param message the message CharSequence to log.%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final CharSequence message) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, (Throwable) null);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a CharSequence at the {@code CUSTOM_LEVEL} level including the stack trace of%n"
-            + "     * the {@link Throwable} {@code t} passed as parameter.%n"
-            + "     * %n"
-            + "     * @param message the CharSequence to log.%n"
-            + "     * @param t the exception to log, including its stack trace.%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final CharSequence message, final Throwable t) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, t);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message object with the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param message the message object to log.%n"
-            + "     */%n"
-            + "    public void methodName(final String message) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, (Throwable) null);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param params parameters to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     */%n"
-            + "    public void methodName(final String message, final Object... params) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, params);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final String message, final Object p0) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, p0);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final String message, final Object p0, "
-            + "final Object p1) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, p0, p1);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final String message, final Object p0, "
-            + "final Object p1, final Object p2) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, p0, p1, p2);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @param p3 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final String message, final Object p0, "
-            + "final Object p1, final Object p2,%n"
-            + "            final Object p3) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, p0, p1, p2, p3);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @param p3 parameter to the message.%n"
-            + "     * @param p4 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final String message, final Object p0, "
-            + "final Object p1, final Object p2,%n"
-            + "            final Object p3, final Object p4) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, p0, p1, p2, p3, p4);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @param p3 parameter to the message.%n"
-            + "     * @param p4 parameter to the message.%n"
-            + "     * @param p5 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final String message, final Object p0, "
-            + "final Object p1, final Object p2,%n"
-            + "            final Object p3, final Object p4, final Object p5) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, p0, p1, p2, p3, p4, p5);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @param p3 parameter to the message.%n"
-            + "     * @param p4 parameter to the message.%n"
-            + "     * @param p5 parameter to the message.%n"
-            + "     * @param p6 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final String message, final Object p0, "
-            + "final Object p1, final Object p2,%n"
-            + "            final Object p3, final Object p4, final Object p5, final Object p6) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, p0, p1, p2, p3, p4, p5, p6);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @param p3 parameter to the message.%n"
-            + "     * @param p4 parameter to the message.%n"
-            + "     * @param p5 parameter to the message.%n"
-            + "     * @param p6 parameter to the message.%n"
-            + "     * @param p7 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final String message, final Object p0, "
-            + "final Object p1, final Object p2,%n"
-            + "            final Object p3, final Object p4, final Object p5, final Object p6,%n"
-            + "            final Object p7) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, p0, p1, p2, p3, p4, p5, p6, p7);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @param p3 parameter to the message.%n"
-            + "     * @param p4 parameter to the message.%n"
-            + "     * @param p5 parameter to the message.%n"
-            + "     * @param p6 parameter to the message.%n"
-            + "     * @param p7 parameter to the message.%n"
-            + "     * @param p8 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final String message, final Object p0, "
-            + "final Object p1, final Object p2,%n"
-            + "            final Object p3, final Object p4, final Object p5, final Object p6,%n"
-            + "            final Object p7, final Object p8) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, p0, p1, p2, p3, p4, p5, p6, p7, "
-            + "p8);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters at the {@code CUSTOM_LEVEL} level.%n"
-            + "     * %n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param p0 parameter to the message.%n"
-            + "     * @param p1 parameter to the message.%n"
-            + "     * @param p2 parameter to the message.%n"
-            + "     * @param p3 parameter to the message.%n"
-            + "     * @param p4 parameter to the message.%n"
-            + "     * @param p5 parameter to the message.%n"
-            + "     * @param p6 parameter to the message.%n"
-            + "     * @param p7 parameter to the message.%n"
-            + "     * @param p8 parameter to the message.%n"
-            + "     * @param p9 parameter to the message.%n"
-            + "     * @see #getMessageFactory()%n"
-            + "     * @since Log4j-2.6%n"
-            + "     */%n"
-            + "    public void methodName(final String message, final Object p0, "
-            + "final Object p1, final Object p2,%n"
-            + "            final Object p3, final Object p4, final Object p5, final Object p6,%n"
-            + "            final Object p7, final Object p8, final Object p9) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, p0, p1, p2, p3, p4, p5, p6, p7, "
-            + "p8, p9);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message at the {@code CUSTOM_LEVEL} level including the stack trace of%n"
-            + "     * the {@link Throwable} {@code t} passed as parameter.%n"
-            + "     * %n"
-            + "     * @param message the message to log.%n"
-            + "     * @param t the exception to log, including its stack trace.%n"
-            + "     */%n"
-            + "    public void methodName(final String message, final Throwable t) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, t);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message which is only to be constructed if the logging level is the {@code CUSTOM_LEVEL}"
-            + "level.%n"
-            + "     *%n"
-            + "     * @param msgSupplier A function, which when called, produces the desired log message;%n"
-            + "     *            the format depends on the message factory.%n"
-            + "     * @since Log4j-2.4%n"
-            + "     */%n"
-            + "    public void methodName(final Supplier> msgSupplier) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msgSupplier, (Throwable) null);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message (only to be constructed if the logging level is the {@code CUSTOM_LEVEL}%n"
-            + "     * level) including the stack trace of the {@link Throwable} t passed as parameter.%n"
-            + "     *%n"
-            + "     * @param msgSupplier A function, which when called, produces the desired log message;%n"
-            + "     *            the format depends on the message factory.%n"
-            + "     * @param t the exception to log, including its stack trace.%n"
-            + "     * @since Log4j-2.4%n"
-            + "     */%n"
-            + "    public void methodName(final Supplier> msgSupplier, final Throwable t) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msgSupplier, t);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message which is only to be constructed if the logging level is the%n"
-            + "     * {@code CUSTOM_LEVEL} level with the specified Marker.%n"
-            + "     *%n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param msgSupplier A function, which when called, produces the desired log message;%n"
-            + "     *            the format depends on the message factory.%n"
-            + "     * @since Log4j-2.4%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final Supplier> msgSupplier) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msgSupplier, (Throwable) null);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters which are only to be constructed if the logging level is the%n"
-            + "     * {@code CUSTOM_LEVEL} level.%n"
-            + "     *%n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param paramSuppliers An array of functions, which when called, produce the desired log"
-            + " message parameters.%n"
-            + "     * @since Log4j-2.4%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final String message, final Supplier>..."
-            + " paramSuppliers) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, paramSuppliers);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message (only to be constructed if the logging level is the {@code CUSTOM_LEVEL}%n"
-            + "     * level) with the specified Marker and including the stack trace of the {@link Throwable}%n"
-            + "     * t passed as parameter.%n"
-            + "     *%n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param msgSupplier A function, which when called, produces the desired log message;%n"
-            + "     *            the format depends on the message factory.%n"
-            + "     * @param t A Throwable or null.%n"
-            + "     * @since Log4j-2.4%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final Supplier> msgSupplier, final Throwable t) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msgSupplier, t);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message with parameters which are only to be constructed if the logging level is%n"
-            + "     * the {@code CUSTOM_LEVEL} level.%n"
-            + "     *%n"
-            + "     * @param message the message to log; the format depends on the message factory.%n"
-            + "     * @param paramSuppliers An array of functions, which when called, produce the desired log"
-            + " message parameters.%n"
-            + "     * @since Log4j-2.4%n"
-            + "     */%n"
-            + "    public void methodName(final String message, final Supplier>... paramSuppliers) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, paramSuppliers);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message which is only to be constructed if the logging level is the%n"
-            + "     * {@code CUSTOM_LEVEL} level with the specified Marker. The {@code MessageSupplier} may or may%n"
-            + "     * not use the {@link MessageFactory} to construct the {@code Message}.%n"
-            + "     *%n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param msgSupplier A function, which when called, produces the desired log message.%n"
-            + "     * @since Log4j-2.4%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final MessageSupplier msgSupplier) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msgSupplier, (Throwable) null);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message (only to be constructed if the logging level is the {@code CUSTOM_LEVEL}%n"
-            + "     * level) with the specified Marker and including the stack trace of the {@link Throwable}%n"
-            + "     * t passed as parameter. The {@code MessageSupplier} may or may not use the%n"
-            + "     * {@link MessageFactory} to construct the {@code Message}.%n"
-            + "     *%n"
-            + "     * @param marker the marker data specific to this log statement%n"
-            + "     * @param msgSupplier A function, which when called, produces the desired log message.%n"
-            + "     * @param t A Throwable or null.%n"
-            + "     * @since Log4j-2.4%n"
-            + "     */%n"
-            + "    public void methodName(final Marker marker, final MessageSupplier msgSupplier, final "
-            + "Throwable t) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msgSupplier, t);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message which is only to be constructed if the logging level is the%n"
-            + "     * {@code CUSTOM_LEVEL} level. The {@code MessageSupplier} may or may not use the%n"
-            + "     * {@link MessageFactory} to construct the {@code Message}.%n"
-            + "     *%n"
-            + "     * @param msgSupplier A function, which when called, produces the desired log message.%n"
-            + "     * @since Log4j-2.4%n"
-            + "     */%n"
-            + "    public void methodName(final MessageSupplier msgSupplier) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msgSupplier, (Throwable) null);%n"
-            + "    }%n"
-            + "%n"
-            + "    /**%n"
-            + "     * Logs a message (only to be constructed if the logging level is the {@code CUSTOM_LEVEL}%n"
-            + "     * level) including the stack trace of the {@link Throwable} t passed as parameter.%n"
-            + "     * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the%n"
-            + "     * {@code Message}.%n"
-            + "     *%n"
-            + "     * @param msgSupplier A function, which when called, produces the desired log message.%n"
-            + "     * @param t the exception to log, including its stack trace.%n"
-            + "     * @since Log4j-2.4%n"
-            + "     */%n"
-            + "    public void methodName(final MessageSupplier msgSupplier, final Throwable t) {%n"
-            + "        logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msgSupplier, t);%n"
-            + "    }%n";
-    // @formatter:on
-
-    private Generate() {}
-
-    /**
-     * Generates source code for custom logger wrappers that only provide convenience methods for the specified custom
-     * levels, not for the standard built-in levels.
-     */
-    public static final class CustomLogger {
-        /**
-         * Generates source code for custom logger wrappers that only provide convenience methods for the specified
-         * custom levels, not for the standard built-in levels.
-         *
-         * @param args className of the custom logger to generate, followed by a NAME=intLevel pair for each custom log
-         *            level to generate convenience methods for
-         */
-        public static void main(final String[] args) {
-            generate(args, Type.CUSTOM);
-        }
-
-        private CustomLogger() {}
-    }
-
-    /**
-     * Generates source code for extended logger wrappers that provide convenience methods for the specified custom
-     * levels, and by extending {@code org.apache.logging.log4j.spi.ExtendedLoggerWrapper}, inherit the convenience
-     * methods for the built-in levels provided by the {@code Logger} interface.
-     */
-    public static final class ExtendedLogger {
-        /**
-         * Generates source code for extended logger wrappers that provide convenience methods for the specified custom
-         * levels.
-         *
-         * @param args className of the custom logger to generate, followed by a NAME=intLevel pair for each custom log
-         *            level to generate convenience methods for
-         */
-        public static void main(final String[] args) {
-            generate(args, Type.EXTEND);
-        }
-
-        private ExtendedLogger() {}
-    }
-
-    static class LevelInfo {
-        final String name;
-        final int intLevel;
-
-        LevelInfo(final String description) {
-            final String[] parts = description.split("=");
-            name = parts[0];
-            intLevel = Integer.parseInt(parts[1]);
-        }
-
-        public static List parse(final List values, final Class> generator) {
-            final List result = new ArrayList<>(values.size());
-            for (int i = 0; i < values.size(); i++) {
-                try {
-                    result.add(new LevelInfo(values.get(i)));
-                } catch (final Exception ex) {
-                    System.err.println("Cannot parse custom level '" + values.get(i) + "': " + ex.toString());
-                    usage(System.err, generator);
-                    System.exit(-1);
-                }
-            }
-            return result;
-        }
-    }
-
-    private static void generate(final String[] args, final Type type) {
-        generate(args, type, System.out);
-    }
-
-    /**
-     * Generates source code for extended logger wrappers that provide convenience methods for the specified custom
-     * levels.
-     *
-     * @param args className of the custom logger to generate, followed by a NAME=intLevel pair for each custom log
-     *            level to generate convenience methods for
-     * @param printStream the stream to write the generated source code to
-     */
-    public static void generateExtend(final String[] args, final PrintStream printStream) {
-        generate(args, Type.EXTEND, printStream);
-    }
-
-    /**
-     * Generates source code for custom logger wrappers that only provide convenience methods for the specified
-     * custom levels, not for the standard built-in levels.
-     *
-     * @param args className of the custom logger to generate, followed by a NAME=intLevel pair for each custom log
-     *            level to generate convenience methods for
-     * @param printStream the stream to write the generated source code to
-     */
-    public static void generateCustom(final String[] args, final PrintStream printStream) {
-        generate(args, Type.CUSTOM, printStream);
-    }
-
-    static void generate(final String[] args, final Type type, final PrintStream printStream) {
-        if (!validate(args)) {
-            usage(printStream, type.generator());
-            System.exit(-1);
-        }
-        final List values = new ArrayList<>(Arrays.asList(args));
-        final String classFQN = values.remove(0);
-        final List levels = LevelInfo.parse(values, type.generator());
-        printStream.println(generateSource(classFQN, levels, type));
-    }
-
-    static boolean validate(final String[] args) {
-        return args.length >= 2;
-    }
-
-    private static void usage(final PrintStream out, final Class> generator) {
-        out.println("Usage: java " + generator.getName() + " className LEVEL1=intLevel1 [LEVEL2=intLevel2...]");
-        out.println("       Where className is the fully qualified class name of the custom/extended logger");
-        out.println("       to generate, followed by a space-separated list of custom log levels.");
-        out.println("       For each custom log level, specify NAME=intLevel (without spaces).");
-    }
-
-    @SuppressFBWarnings(
-            value = "FORMAT_STRING_MANIPULATION",
-            justification = "The format strings come from constants. The replacement is done for readability.")
-    static String generateSource(final String classNameFQN, final List levels, final Type type) {
-        final StringBuilder sb = new StringBuilder(10000 * levels.size());
-        final int lastDot = classNameFQN.lastIndexOf('.');
-        final String pkg = classNameFQN.substring(0, Math.max(lastDot, 0));
-        if (!pkg.isEmpty()) {
-            sb.append(String.format(PACKAGE_DECLARATION, pkg));
-        }
-        sb.append(String.format(type.imports(), ""));
-        final String className = classNameFQN.substring(classNameFQN.lastIndexOf('.') + 1);
-        final String javadocDescr = javadocDescription(levels);
-        sb.append(String.format(type.declaration(), javadocDescr, className));
-        sb.append(String.format(FQCN_FIELD, className));
-        for (final LevelInfo level : levels) {
-            sb.append(String.format(LEVEL_FIELD, level.name, level.name, level.intLevel));
-        }
-        sb.append(String.format(type.constructor(), className));
-        sb.append(String.format(FACTORY_METHODS.replaceAll("CLASSNAME", className), ""));
-        for (final LevelInfo level : levels) {
-            final String methodName = camelCase(level.name);
-            final String phase1 = METHODS.replaceAll("CUSTOM_LEVEL", level.name);
-            final String phase2 = phase1.replaceAll("methodName", methodName);
-            sb.append(String.format(phase2, ""));
-        }
-
-        sb.append('}');
-        sb.append(System.getProperty("line.separator"));
-        return sb.toString();
-    }
-
-    static String javadocDescription(final List levels) {
-        if (levels.size() == 1) {
-            return "the " + levels.get(0).name + " custom log level.";
-        }
-        final StringBuilder sb = new StringBuilder(512);
-        sb.append("the ");
-        String sep = "";
-        for (int i = 0; i < levels.size(); i++) {
-            sb.append(sep);
-            sb.append(levels.get(i).name);
-            sep = (i == levels.size() - 2) ? " and " : ", ";
-        }
-        sb.append(" custom log levels.");
-        return sb.toString();
-    }
-
-    static String camelCase(final String customLevel) {
-        final StringBuilder sb = new StringBuilder(customLevel.length());
-        boolean lower = true;
-        for (final char ch : customLevel.toCharArray()) {
-            if (ch == '_') {
-                lower = false;
-                continue;
-            }
-            sb.append(lower ? Character.toLowerCase(ch) : Character.toUpperCase(ch));
-            lower = true;
-        }
-        return sb.toString();
-    }
-}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/package-info.java
deleted file mode 100644
index 8cbd2eb92fa..00000000000
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/package-info.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-/**
- * Log4j 2 command line tools.
- */
-@Export
-@Version("2.20.1")
-package org.apache.logging.log4j.core.tools;
-
-import org.osgi.annotation.bundle.Export;
-import org.osgi.annotation.versioning.Version;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/picocli/CommandLine.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/picocli/CommandLine.java
deleted file mode 100644
index 37b5b46bf26..00000000000
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/picocli/CommandLine.java
+++ /dev/null
@@ -1,5619 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.logging.log4j.core.tools.picocli;
-
-import static org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.SPAN;
-import static org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.TRUNCATE;
-import static org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.WRAP;
-import static org.apache.logging.log4j.util.Strings.toRootLowerCase;
-import static org.apache.logging.log4j.util.Strings.toRootUpperCase;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import java.io.File;
-import java.io.PrintStream;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.WildcardType;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.net.InetAddress;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.charset.Charset;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.sql.Time;
-import java.text.BreakIterator;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Queue;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.Stack;
-import java.util.TreeSet;
-import java.util.UUID;
-import java.util.concurrent.Callable;
-import java.util.regex.Pattern;
-import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.IStyle;
-import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.Style;
-import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.Text;
-
-/**
- * 
- * CommandLine interpreter that uses reflection to initialize an annotated domain object with values obtained from the
- * command line arguments.
- * 
Example 
- * import static picocli.CommandLine.*;
- *
- * @Command(header = "Encrypt FILE(s), or standard input, to standard output or to the output file.",
- *          version = "v1.2.3")
- * public class Encrypt {
- *
- *     @Parameters(type = File.class, description = "Any number of input files")
- *     private List<File> files = new ArrayList<File>();
- *
- *     @Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
- *     private File outputFile;
- *
- *     @Option(names = { "-v", "--verbose"}, description = "Verbosely list files processed")
- *     private boolean verbose;
- *
- *     @Option(names = { "-h", "--help", "-?", "-help"}, usageHelp = true, description = "Display this help and exit")
- *     private boolean help;
- *
- *     @Option(names = { "-V", "--version"}, versionHelp = true, description = "Display version info and exit")
- *     private boolean versionHelp;
- * }
- *  
- * 
- * Use {@code CommandLine} to initialize a domain object as follows:
- * 
- * public static void main(String... args) {
- *     Encrypt encrypt = new Encrypt();
- *     try {
- *         List<CommandLine> parsedCommands = new CommandLine(encrypt).parse(args);
- *         if (!CommandLine.printHelpIfRequested(parsedCommands, System.err, Help.Ansi.AUTO)) {
- *             runProgram(encrypt);
- *         }
- *     } catch (ParameterException ex) { // command line arguments could not be parsed
- *         System.err.println(ex.getMessage());
- *         ex.getCommandLine().usage(System.err);
- *     }
- * }
- *  
- * Invoke the above program with some command line arguments. The below are all equivalent:
- * 
- * 
- * --verbose --out=outfile in1 in2
- * --verbose --out outfile in1 in2
- * -v --out=outfile in1 in2
- * -v -o outfile in1 in2
- * -v -o=outfile in1 in2
- * -vo outfile in1 in2
- * -vo=outfile in1 in2
- * -v -ooutfile in1 in2
- * -vooutfile in1 in2
- *  
- */
-public class CommandLine {
-    /** This is picocli version {@value}. */
-    public static final String VERSION = "2.0.3";
-
-    private final Tracer tracer = new Tracer();
-    private final Interpreter interpreter;
-    private String commandName = Help.DEFAULT_COMMAND_NAME;
-    private boolean overwrittenOptionsAllowed = false;
-    private boolean unmatchedArgumentsAllowed = false;
-    private final List unmatchedArguments = new ArrayList();
-    private CommandLine parent;
-    private boolean usageHelpRequested;
-    private boolean versionHelpRequested;
-    private final List versionLines = new ArrayList();
-
-    /**
-     * Constructs a new {@code CommandLine} interpreter with the specified annotated object.
-     * When the {@link #parse(String...)} method is called, fields of the specified object that are annotated
-     * with {@code @Option} or {@code @Parameters} will be initialized based on command line arguments.
-     * @param command the object to initialize from the command line arguments
-     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
-     */
-    public CommandLine(final Object command) {
-        interpreter = new Interpreter(command);
-    }
-
-    /** Registers a subcommand with the specified name. For example:
-     * 
-     * CommandLine commandLine = new CommandLine(new Git())
-     *         .addSubcommand("status",   new GitStatus())
-     *         .addSubcommand("commit",   new GitCommit();
-     *         .addSubcommand("add",      new GitAdd())
-     *         .addSubcommand("branch",   new GitBranch())
-     *         .addSubcommand("checkout", new GitCheckout())
-     *         //...
-     *         ;
-     *  
-     *
-     * The specified object can be an annotated object or a
-     * {@code CommandLine} instance with its own nested subcommands. For example:
-     * 
-     * CommandLine commandLine = new CommandLine(new MainCommand())
-     *         .addSubcommand("cmd1",                 new ChildCommand1()) // subcommand
-     *         .addSubcommand("cmd2",                 new ChildCommand2())
-     *         .addSubcommand("cmd3", new CommandLine(new ChildCommand3()) // subcommand with nested sub-subcommands
-     *                 .addSubcommand("cmd3sub1",                 new GrandChild3Command1())
-     *                 .addSubcommand("cmd3sub2",                 new GrandChild3Command2())
-     *                 .addSubcommand("cmd3sub3", new CommandLine(new GrandChild3Command3()) // deeper nesting
-     *                         .addSubcommand("cmd3sub3sub1", new GreatGrandChild3Command3_1())
-     *                         .addSubcommand("cmd3sub3sub2", new GreatGrandChild3Command3_2())
-     *                 )
-     *         );
-     *  
-     * The default type converters are available on all subcommands and nested sub-subcommands, but custom type
-     * converters are registered only with the subcommand hierarchy as it existed when the custom type was registered.
-     * To ensure a custom type converter is available to all subcommands, register the type converter last, after
-     * adding subcommands.
-     * See also the {@link Command#subcommands()} annotation to register subcommands declaratively.
-     *
-     * @param name the string to recognize on the command line as a subcommand
-     * @param command the object to initialize with command line arguments following the subcommand name.
-     *          This may be a {@code CommandLine} instance with its own (nested) subcommands
-     * @return this CommandLine object, to allow method chaining
-     * @see #registerConverter(Class, ITypeConverter)
-     * @since 0.9.7
-     * @see Command#subcommands()
-     */
-    public CommandLine addSubcommand(final String name, final Object command) {
-        final CommandLine commandLine = toCommandLine(command);
-        commandLine.parent = this;
-        interpreter.commands.put(name, commandLine);
-        return this;
-    }
-    /** Returns a map with the subcommands {@linkplain #addSubcommand(String, Object) registered} on this instance.
-     * @return a map with the registered subcommands
-     * @since 0.9.7
-     */
-    public Map getSubcommands() {
-        return new LinkedHashMap(interpreter.commands);
-    }
-    /**
-     * Returns the command that this is a subcommand of, or {@code null} if this is a top-level command.
-     * @return the command that this is a subcommand of, or {@code null} if this is a top-level command
-     * @see #addSubcommand(String, Object)
-     * @see Command#subcommands()
-     * @since 0.9.8
-     */
-    public CommandLine getParent() {
-        return parent;
-    }
-
-    /** Returns the annotated object that this {@code CommandLine} instance was constructed with.
-     * @param  the type of the variable that the return value is being assigned to
-     * @return the annotated object that this {@code CommandLine} instance was constructed with
-     * @since 0.9.7
-     */
-    public  T getCommand() {
-        return (T) interpreter.command;
-    }
-
-    /** Returns {@code true} if an option annotated with {@link Option#usageHelp()} was specified on the command line.
-     * @return whether the parser encountered an option annotated with {@link Option#usageHelp()}.
-     * @since 0.9.8 */
-    public boolean isUsageHelpRequested() {
-        return usageHelpRequested;
-    }
-
-    /** Returns {@code true} if an option annotated with {@link Option#versionHelp()} was specified on the command line.
-     * @return whether the parser encountered an option annotated with {@link Option#versionHelp()}.
-     * @since 0.9.8 */
-    public boolean isVersionHelpRequested() {
-        return versionHelpRequested;
-    }
-
-    /** Returns whether options for single-value fields can be specified multiple times on the command line.
-     * The default is {@code false} and a {@link OverwrittenOptionException} is thrown if this happens.
-     * When {@code true}, the last specified value is retained.
-     * @return {@code true} if options for single-value fields can be specified multiple times on the command line, {@code false} otherwise
-     * @since 0.9.7
-     */
-    public boolean isOverwrittenOptionsAllowed() {
-        return overwrittenOptionsAllowed;
-    }
-
-    /** Sets whether options for single-value fields can be specified multiple times on the command line without a {@link OverwrittenOptionException} being thrown.
-     * The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
-     * subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
-     * later will have the default setting. To ensure a setting is applied to all
-     * subcommands, call the setter last, after adding subcommands.
-     * @param newValue the new setting
-     * @return this {@code CommandLine} object, to allow method chaining
-     * @since 0.9.7
-     */
-    public CommandLine setOverwrittenOptionsAllowed(final boolean newValue) {
-        this.overwrittenOptionsAllowed = newValue;
-        for (final CommandLine command : interpreter.commands.values()) {
-            command.setOverwrittenOptionsAllowed(newValue);
-        }
-        return this;
-    }
-
-    /** Returns whether the end user may specify arguments on the command line that are not matched to any option or parameter fields.
-     * The default is {@code false} and a {@link UnmatchedArgumentException} is thrown if this happens.
-     * When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method.
-     * @return {@code true} if the end use may specify unmatched arguments on the command line, {@code false} otherwise
-     * @see #getUnmatchedArguments()
-     * @since 0.9.7
-     */
-    public boolean isUnmatchedArgumentsAllowed() {
-        return unmatchedArgumentsAllowed;
-    }
-
-    /** Sets whether the end user may specify unmatched arguments on the command line without a {@link UnmatchedArgumentException} being thrown.
-     * The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
-     * subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
-     * later will have the default setting. To ensure a setting is applied to all
-     * subcommands, call the setter last, after adding subcommands.
-     * @param newValue the new setting. When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method.
-     * @return this {@code CommandLine} object, to allow method chaining
-     * @since 0.9.7
-     * @see #getUnmatchedArguments()
-     */
-    public CommandLine setUnmatchedArgumentsAllowed(final boolean newValue) {
-        this.unmatchedArgumentsAllowed = newValue;
-        for (final CommandLine command : interpreter.commands.values()) {
-            command.setUnmatchedArgumentsAllowed(newValue);
-        }
-        return this;
-    }
-
-    /** Returns the list of unmatched command line arguments, if any.
-     * @return the list of unmatched command line arguments or an empty list
-     * @see #isUnmatchedArgumentsAllowed()
-     * @since 0.9.7
-     */
-    public List getUnmatchedArguments() {
-        return unmatchedArguments;
-    }
-
-    /**
-     * 
-     * Convenience method that initializes the specified annotated object from the specified command line arguments.
-     * 
-     * This is equivalent to
-     * 
-     * CommandLine cli = new CommandLine(command);
-     * cli.parse(args);
-     * return command;
-     *  
-     *
-     * @param command the object to initialize. This object contains fields annotated with
-     *          {@code @Option} or {@code @Parameters}.
-     * @param args the command line arguments to parse
-     * @param  the type of the annotated object
-     * @return the specified annotated object
-     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
-     * @throws ParameterException if the specified command line arguments are invalid
-     * @since 0.9.7
-     */
-    public static  T populateCommand(final T command, final String... args) {
-        final CommandLine cli = toCommandLine(command);
-        cli.parse(args);
-        return command;
-    }
-
-    /** Parses the specified command line arguments and returns a list of {@code CommandLine} objects representing the
-     * top-level command and any subcommands (if any) that were recognized and initialized during the parsing process.
-     * 
-     * If parsing succeeds, the first element in the returned list is always {@code this CommandLine} object. The
-     * returned list may contain more elements if subcommands were {@linkplain #addSubcommand(String, Object) registered}
-     * and these subcommands were initialized by matching command line arguments. If parsing fails, a
-     * {@link ParameterException} is thrown.
-     * 
-     *
-     * @param args the command line arguments to parse
-     * @return a list with the top-level command and any subcommands initialized by this method
-     * @throws ParameterException if the specified command line arguments are invalid; use
-     *      {@link ParameterException#getCommandLine()} to get the command or subcommand whose user input was invalid
-     */
-    public List parse(final String... args) {
-        return interpreter.parse(args);
-    }
-    /**
-     * Represents a function that can process a List of {@code CommandLine} objects resulting from successfully
-     * {@linkplain #parse(String...) parsing} the command line arguments. This is a
-     * functional interface 
-     * whose functional method is {@link #handleParseResult(List, PrintStream, CommandLine.Help.Ansi)}.
-     * 
-     * Implementations of this functions can be passed to the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) CommandLine::parseWithHandler}
-     * methods to take some next step after the command line was successfully parsed.
-     * 
-     * @see RunFirst
-     * @see RunLast
-     * @see RunAll
-     * @since 2.0 */
-    public interface IParseResultHandler {
-        /** Processes a List of {@code CommandLine} objects resulting from successfully
-         * {@linkplain #parse(String...) parsing} the command line arguments and optionally returns a list of results.
-         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
-         * @param out the {@code PrintStream} to print help to if requested
-         * @param ansi for printing help messages using ANSI styles and colors
-         * @return a list of results, or an empty list if there are no results
-         * @throws ExecutionException if a problem occurred while processing the parse results; use
-         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
-         */
-        List handleParseResult(List parsedCommands, PrintStream out, Help.Ansi ansi)
-                throws ExecutionException;
-    }
-    /**
-     * Represents a function that can handle a {@code ParameterException} that occurred while
-     * {@linkplain #parse(String...) parsing} the command line arguments. This is a
-     * functional interface 
-     * whose functional method is {@link #handleException(CommandLine.ParameterException, PrintStream, CommandLine.Help.Ansi, String...)}.
-     * 
-     * Implementations of this functions can be passed to the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) CommandLine::parseWithHandler}
-     * methods to handle situations when the command line could not be parsed.
-     * 
-     * @see DefaultExceptionHandler
-     * @since 2.0 */
-    public interface IExceptionHandler {
-        /** Handles a {@code ParameterException} that occurred while {@linkplain #parse(String...) parsing} the command
-         * line arguments and optionally returns a list of results.
-         * @param ex the ParameterException describing the problem that occurred while parsing the command line arguments,
-         *           and the CommandLine representing the command or subcommand whose input was invalid
-         * @param out the {@code PrintStream} to print help to if requested
-         * @param ansi for printing help messages using ANSI styles and colors
-         * @param args the command line arguments that could not be parsed
-         * @return a list of results, or an empty list if there are no results
-         */
-        List handleException(ParameterException ex, PrintStream out, Help.Ansi ansi, String... args);
-    }
-    /**
-     * Default exception handler that prints the exception message to the specified {@code PrintStream}, followed by the
-     * usage message for the command or subcommand whose input was invalid.
-     * Implementation roughly looks like this:
-     * 
-     *     System.err.println(paramException.getMessage());
-     *     paramException.getCommandLine().usage(System.err);
-     *  
-     * @since 2.0 */
-    public static class DefaultExceptionHandler implements IExceptionHandler {
-        @Override
-        public List handleException(
-                final ParameterException ex, final PrintStream out, final Help.Ansi ansi, final String... args) {
-            out.println(ex.getMessage());
-            ex.getCommandLine().usage(out, ansi);
-            return Collections.emptyList();
-        }
-    }
-    /**
-     * Helper method that may be useful when processing the list of {@code CommandLine} objects that result from successfully
-     * {@linkplain #parse(String...) parsing} command line arguments. This method prints out
-     * {@linkplain #usage(PrintStream, Help.Ansi) usage help} if {@linkplain #isUsageHelpRequested() requested}
-     * or {@linkplain #printVersionHelp(PrintStream, Help.Ansi) version help} if {@linkplain #isVersionHelpRequested() requested}
-     * and returns {@code true}. Otherwise, if none of the specified {@code CommandLine} objects have help requested,
-     * this method returns {@code false}.
-     * 
-     * Note that this method only  looks at the {@link Option#usageHelp() usageHelp} and
-     * {@link Option#versionHelp() versionHelp} attributes. The {@link Option#help() help} attribute is ignored.
-     * 
-     * @param parsedCommands the list of {@code CommandLine} objects to check if help was requested
-     * @param out the {@code PrintStream} to print help to if requested
-     * @param ansi for printing help messages using ANSI styles and colors
-     * @return {@code true} if help was printed, {@code false} otherwise
-     * @since 2.0 */
-    public static boolean printHelpIfRequested(
-            final List parsedCommands, final PrintStream out, final Help.Ansi ansi) {
-        for (final CommandLine parsed : parsedCommands) {
-            if (parsed.isUsageHelpRequested()) {
-                parsed.usage(out, ansi);
-                return true;
-            } else if (parsed.isVersionHelpRequested()) {
-                parsed.printVersionHelp(out, ansi);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static Object execute(final CommandLine parsed) {
-        final Object command = parsed.getCommand();
-        if (command instanceof Runnable) {
-            try {
-                ((Runnable) command).run();
-                return null;
-            } catch (final Exception ex) {
-                throw new ExecutionException(parsed, "Error while running command (" + command + ")", ex);
-            }
-        } else if (command instanceof Callable) {
-            try {
-                return ((Callable) command).call();
-            } catch (final Exception ex) {
-                throw new ExecutionException(parsed, "Error while calling command (" + command + ")", ex);
-            }
-        }
-        throw new ExecutionException(parsed, "Parsed command (" + command + ") is not Runnable or Callable");
-    }
-    /**
-     * Command line parse result handler that prints help if requested, and otherwise executes the top-level
-     * {@code Runnable} or {@code Callable} command.
-     * For use in the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) parseWithHandler} methods.
-     * 
-     * From picocli v2.0, {@code RunFirst} is used to implement the {@link #run(Runnable, PrintStream, Help.Ansi, String...) run}
-     * and {@link #call(Callable, PrintStream, Help.Ansi, String...) call} convenience methods.
-     * 
-     * @since 2.0 */
-    public static class RunFirst implements IParseResultHandler {
-        /** Prints help if requested, and otherwise executes the top-level {@code Runnable} or {@code Callable} command.
-         * If the top-level command does not implement either {@code Runnable} or {@code Callable}, a {@code ExecutionException}
-         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
-         *
-         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
-         * @param out the {@code PrintStream} to print help to if requested
-         * @param ansi for printing help messages using ANSI styles and colors
-         * @return an empty list if help was requested, or a list containing a single element: the result of calling the
-         *      {@code Callable}, or a {@code null} element if the top-level command was a {@code Runnable}
-         * @throws ExecutionException if a problem occurred while processing the parse results; use
-         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
-         */
-        @Override
-        public List handleParseResult(
-                final List parsedCommands, final PrintStream out, final Help.Ansi ansi) {
-            if (printHelpIfRequested(parsedCommands, out, ansi)) {
-                return Collections.emptyList();
-            }
-            return Arrays.asList(execute(parsedCommands.get(0)));
-        }
-    }
-    /**
-     * Command line parse result handler that prints help if requested, and otherwise executes the most specific
-     * {@code Runnable} or {@code Callable} subcommand.
-     * For use in the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) parseWithHandler} methods.
-     * 
-     * Something like this:
-     * 
-     *     // RunLast implementation: print help if requested, otherwise execute the most specific subcommand
-     *     if (CommandLine.printHelpIfRequested(parsedCommands, System.err, Help.Ansi.AUTO)) {
-     *         return emptyList();
-     *     }
-     *     CommandLine last = parsedCommands.get(parsedCommands.size() - 1);
-     *     Object command = last.getCommand();
-     *     if (command instanceof Runnable) {
-     *         try {
-     *             ((Runnable) command).run();
-     *         } catch (Exception ex) {
-     *             throw new ExecutionException(last, "Error in runnable " + command, ex);
-     *         }
-     *     } else if (command instanceof Callable) {
-     *         Object result;
-     *         try {
-     *             result = ((Callable) command).call();
-     *         } catch (Exception ex) {
-     *             throw new ExecutionException(last, "Error in callable " + command, ex);
-     *         }
-     *         // ...do something with result
-     *     } else {
-     *         throw new ExecutionException(last, "Parsed command (" + command + ") is not Runnable or Callable");
-     *     }
-     *  
-     * @since 2.0 */
-    public static class RunLast implements IParseResultHandler {
-        /** Prints help if requested, and otherwise executes the most specific {@code Runnable} or {@code Callable} subcommand.
-         * If the last (sub)command does not implement either {@code Runnable} or {@code Callable}, a {@code ExecutionException}
-         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
-         *
-         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
-         * @param out the {@code PrintStream} to print help to if requested
-         * @param ansi for printing help messages using ANSI styles and colors
-         * @return an empty list if help was requested, or a list containing a single element: the result of calling the
-         *      {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable}
-         * @throws ExecutionException if a problem occurred while processing the parse results; use
-         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
-         */
-        @Override
-        public List handleParseResult(
-                final List parsedCommands, final PrintStream out, final Help.Ansi ansi) {
-            if (printHelpIfRequested(parsedCommands, out, ansi)) {
-                return Collections.emptyList();
-            }
-            final CommandLine last = parsedCommands.get(parsedCommands.size() - 1);
-            return Arrays.asList(execute(last));
-        }
-    }
-    /**
-     * Command line parse result handler that prints help if requested, and otherwise executes the top-level command and
-     * all subcommands as {@code Runnable} or {@code Callable}.
-     * For use in the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) parseWithHandler} methods.
-     * @since 2.0 */
-    public static class RunAll implements IParseResultHandler {
-        /** Prints help if requested, and otherwise executes the top-level command and all subcommands as {@code Runnable}
-         * or {@code Callable}. If any of the {@code CommandLine} commands does not implement either
-         * {@code Runnable} or {@code Callable}, a {@code ExecutionException}
-         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
-         *
-         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
-         * @param out the {@code PrintStream} to print help to if requested
-         * @param ansi for printing help messages using ANSI styles and colors
-         * @return an empty list if help was requested, or a list containing the result of executing all commands:
-         *      the return values from calling the {@code Callable} commands, {@code null} elements for commands that implement {@code Runnable}
-         * @throws ExecutionException if a problem occurred while processing the parse results; use
-         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
-         */
-        @Override
-        public List handleParseResult(
-                final List parsedCommands, final PrintStream out, final Help.Ansi ansi) {
-            if (printHelpIfRequested(parsedCommands, out, ansi)) {
-                return null;
-            }
-            final List result = new ArrayList();
-            for (final CommandLine parsed : parsedCommands) {
-                result.add(execute(parsed));
-            }
-            return result;
-        }
-    }
-    /**
-     * Returns the result of calling {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...)}
-     * with {@code Help.Ansi.AUTO} and a new {@link DefaultExceptionHandler} in addition to the specified parse result handler,
-     * {@code PrintStream}, and the specified command line arguments.
-     * 
-     * This is a convenience method intended to offer the same ease of use as the {@link #run(Runnable, PrintStream, Help.Ansi, String...) run}
-     * and {@link #call(Callable, PrintStream, Help.Ansi, String...) call} methods, but with more flexibility and better
-     * support for nested subcommands.
-     * 
-     * Calling this method roughly expands to:
-     * 
-     * try {
-     *     List<CommandLine> parsedCommands = parse(args);
-     *     return parseResultsHandler.handleParseResult(parsedCommands, out, Help.Ansi.AUTO);
-     * } catch (ParameterException ex) {
-     *     return new DefaultExceptionHandler().handleException(ex, out, ansi, args);
-     * }
-     *  
-     * 
-     * Picocli provides some default handlers that allow you to accomplish some common tasks with very little code.
-     * The following handlers are available:
-     * 
-     *   {@link RunLast} handler prints help if requested, and otherwise gets the last specified command or subcommand
-     * and tries to execute it as a {@code Runnable} or {@code Callable}. 
-     *   {@link RunFirst} handler prints help if requested, and otherwise executes the top-level command as a {@code Runnable} or {@code Callable}. 
-     *   {@link RunAll} handler prints help if requested, and otherwise executes all recognized commands and subcommands as {@code Runnable} or {@code Callable} tasks. 
-     *   {@link DefaultExceptionHandler} prints the error message followed by usage help 
-     *  
-     * @param handler the function that will process the result of successfully parsing the command line arguments
-     * @param out the {@code PrintStream} to print help to if requested
-     * @param args the command line arguments
-     * @return a list of results, or an empty list if there are no results
-     * @throws ExecutionException if the command line arguments were parsed successfully but a problem occurred while processing the
-     *      parse results; use {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
-     * @see RunLast
-     * @see RunAll
-     * @since 2.0 */
-    public List parseWithHandler(
-            final IParseResultHandler handler, final PrintStream out, final String... args) {
-        return parseWithHandlers(handler, out, Help.Ansi.AUTO, new DefaultExceptionHandler(), args);
-    }
-    /**
-     * Tries to {@linkplain #parse(String...) parse} the specified command line arguments, and if successful, delegates
-     * the processing of the resulting list of {@code CommandLine} objects to the specified {@linkplain IParseResultHandler handler}.
-     * If the command line arguments were invalid, the {@code ParameterException} thrown from the {@code parse} method
-     * is caught and passed to the specified {@link IExceptionHandler}.
-     * 
-     * This is a convenience method intended to offer the same ease of use as the {@link #run(Runnable, PrintStream, Help.Ansi, String...) run}
-     * and {@link #call(Callable, PrintStream, Help.Ansi, String...) call} methods, but with more flexibility and better
-     * support for nested subcommands.
-     * 
-     * Calling this method roughly expands to:
-     * 
-     * try {
-     *     List<CommandLine> parsedCommands = parse(args);
-     *     return parseResultsHandler.handleParseResult(parsedCommands, out, ansi);
-     * } catch (ParameterException ex) {
-     *     return new exceptionHandler.handleException(ex, out, ansi, args);
-     * }
-     *  
-     * 
-     * Picocli provides some default handlers that allow you to accomplish some common tasks with very little code.
-     * The following handlers are available:
-     * 
-     *   {@link RunLast} handler prints help if requested, and otherwise gets the last specified command or subcommand
-     * and tries to execute it as a {@code Runnable} or {@code Callable}. 
-     *   {@link RunFirst} handler prints help if requested, and otherwise executes the top-level command as a {@code Runnable} or {@code Callable}. 
-     *   {@link RunAll} handler prints help if requested, and otherwise executes all recognized commands and subcommands as {@code Runnable} or {@code Callable} tasks. 
-     *   {@link DefaultExceptionHandler} prints the error message followed by usage help 
-     *  
-     *
-     * @param handler the function that will process the result of successfully parsing the command line arguments
-     * @param out the {@code PrintStream} to print help to if requested
-     * @param ansi for printing help messages using ANSI styles and colors
-     * @param exceptionHandler the function that can handle the {@code ParameterException} thrown when the command line arguments are invalid
-     * @param args the command line arguments
-     * @return a list of results produced by the {@code IParseResultHandler} or the {@code IExceptionHandler}, or an empty list if there are no results
-     * @throws ExecutionException if the command line arguments were parsed successfully but a problem occurred while processing the parse
-     *      result {@code CommandLine} objects; use {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
-     * @see RunLast
-     * @see RunAll
-     * @see DefaultExceptionHandler
-     * @since 2.0 */
-    public List parseWithHandlers(
-            final IParseResultHandler handler,
-            final PrintStream out,
-            final Help.Ansi ansi,
-            final IExceptionHandler exceptionHandler,
-            final String... args) {
-        try {
-            final List result = parse(args);
-            return handler.handleParseResult(result, out, ansi);
-        } catch (final ParameterException ex) {
-            return exceptionHandler.handleException(ex, out, ansi, args);
-        }
-    }
-    /**
-     * Equivalent to {@code new CommandLine(command).usage(out)}. See {@link #usage(PrintStream)} for details.
-     * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters}
-     * @param out the print stream to print the help message to
-     * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
-     */
-    public static void usage(final Object command, final PrintStream out) {
-        toCommandLine(command).usage(out);
-    }
-
-    /**
-     * Equivalent to {@code new CommandLine(command).usage(out, ansi)}.
-     * See {@link #usage(PrintStream, Help.Ansi)} for details.
-     * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters}
-     * @param out the print stream to print the help message to
-     * @param ansi whether the usage message should contain ANSI escape codes or not
-     * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
-     */
-    public static void usage(final Object command, final PrintStream out, final Help.Ansi ansi) {
-        toCommandLine(command).usage(out, ansi);
-    }
-
-    /**
-     * Equivalent to {@code new CommandLine(command).usage(out, colorScheme)}.
-     * See {@link #usage(PrintStream, Help.ColorScheme)} for details.
-     * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters}
-     * @param out the print stream to print the help message to
-     * @param colorScheme the {@code ColorScheme} defining the styles for options, parameters and commands when ANSI is enabled
-     * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
-     */
-    public static void usage(final Object command, final PrintStream out, final Help.ColorScheme colorScheme) {
-        toCommandLine(command).usage(out, colorScheme);
-    }
-
-    /**
-     * Delegates to {@link #usage(PrintStream, Help.Ansi)} with the {@linkplain Help.Ansi#AUTO platform default}.
-     * @param out the printStream to print to
-     * @see #usage(PrintStream, Help.ColorScheme)
-     */
-    public void usage(final PrintStream out) {
-        usage(out, Help.Ansi.AUTO);
-    }
-
-    /**
-     * Delegates to {@link #usage(PrintStream, Help.ColorScheme)} with the {@linkplain Help#defaultColorScheme(CommandLine.Help.Ansi) default color scheme}.
-     * @param out the printStream to print to
-     * @param ansi whether the usage message should include ANSI escape codes or not
-     * @see #usage(PrintStream, Help.ColorScheme)
-     */
-    public void usage(final PrintStream out, final Help.Ansi ansi) {
-        usage(out, Help.defaultColorScheme(ansi));
-    }
-    /**
-     * Prints a usage help message for the annotated command class to the specified {@code PrintStream}.
-     * Delegates construction of the usage help message to the {@link Help} inner class and is equivalent to:
-     * 
-     * Help help = new Help(command).addAllSubcommands(getSubcommands());
-     * StringBuilder sb = new StringBuilder()
-     *         .append(help.headerHeading())
-     *         .append(help.header())
-     *         .append(help.synopsisHeading())      //e.g. Usage:
-     *         .append(help.synopsis())             //e.g. <main class> [OPTIONS] <command> [COMMAND-OPTIONS] [ARGUMENTS]
-     *         .append(help.descriptionHeading())   //e.g. %nDescription:%n%n
-     *         .append(help.description())          //e.g. {"Converts foos to bars.", "Use options to control conversion mode."}
-     *         .append(help.parameterListHeading()) //e.g. %nPositional parameters:%n%n
-     *         .append(help.parameterList())        //e.g. [FILE...] the files to convert
-     *         .append(help.optionListHeading())    //e.g. %nOptions:%n%n
-     *         .append(help.optionList())           //e.g. -h, --help   displays this help and exits
-     *         .append(help.commandListHeading())   //e.g. %nCommands:%n%n
-     *         .append(help.commandList())          //e.g.    add       adds the frup to the frooble
-     *         .append(help.footerHeading())
-     *         .append(help.footer());
-     * out.print(sb);
-     *  
-     * Annotate your class with {@link Command} to control many aspects of the usage help message, including
-     * the program name, text of section headings and section contents, and some aspects of the auto-generated sections
-     * of the usage help message.
-     * 
To customize the auto-generated sections of the usage help message, like how option details are displayed,
-     * instantiate a {@link Help} object and use a {@link Help.TextTable} with more of fewer columns, a custom
-     * {@linkplain Help.Layout layout}, and/or a custom option {@linkplain Help.IOptionRenderer renderer}
-     * for ultimate control over which aspects of an Option or Field are displayed where.
-     * @param out the {@code PrintStream} to print the usage help message to
-     * @param colorScheme the {@code ColorScheme} defining the styles for options, parameters and commands when ANSI is enabled
-     */
-    public void usage(final PrintStream out, final Help.ColorScheme colorScheme) {
-        final Help help = new Help(interpreter.command, colorScheme).addAllSubcommands(getSubcommands());
-        if (!Help.DEFAULT_SEPARATOR.equals(getSeparator())) {
-            help.separator = getSeparator();
-            help.parameterLabelRenderer = help.createDefaultParamLabelRenderer(); // update for new separator
-        }
-        if (!Help.DEFAULT_COMMAND_NAME.equals(getCommandName())) {
-            help.commandName = getCommandName();
-        }
-        final StringBuilder sb = new StringBuilder()
-                .append(help.headerHeading())
-                .append(help.header())
-                .append(help.synopsisHeading()) // e.g. Usage:
-                .append(help.synopsis(
-                        help.synopsisHeadingLength())) // e.g. <main class> [OPTIONS] <command>
-                // [COMMAND-OPTIONS] [ARGUMENTS]
-                .append(help.descriptionHeading()) // e.g. %nDescription:%n%n
-                .append(help.description()) // e.g. {"Converts foos to bars.", "Use options to control conversion
-                // mode."}
-                .append(help.parameterListHeading()) // e.g. %nPositional parameters:%n%n
-                .append(help.parameterList()) // e.g. [FILE...] the files to convert
-                .append(help.optionListHeading()) // e.g. %nOptions:%n%n
-                .append(help.optionList()) // e.g. -h, --help   displays this help and exits
-                .append(help.commandListHeading()) // e.g. %nCommands:%n%n
-                .append(help.commandList()) // e.g.    add       adds the frup to the frooble
-                .append(help.footerHeading())
-                .append(help.footer());
-        out.print(sb);
-    }
-
-    /**
-     * Delegates to {@link #printVersionHelp(PrintStream, Help.Ansi)} with the {@linkplain Help.Ansi#AUTO platform default}.
-     * @param out the printStream to print to
-     * @see #printVersionHelp(PrintStream, Help.Ansi)
-     * @since 0.9.8
-     */
-    public void printVersionHelp(final PrintStream out) {
-        printVersionHelp(out, Help.Ansi.AUTO);
-    }
-
-    /**
-     * Prints version information from the {@link Command#version()} annotation to the specified {@code PrintStream}.
-     * Each element of the array of version strings is printed on a separate line. Version strings may contain
-     * markup for colors and style .
-     * @param out the printStream to print to
-     * @param ansi whether the usage message should include ANSI escape codes or not
-     * @see Command#version()
-     * @see Option#versionHelp()
-     * @see #isVersionHelpRequested()
-     * @since 0.9.8
-     */
-    public void printVersionHelp(final PrintStream out, final Help.Ansi ansi) {
-        for (final String versionInfo : versionLines) {
-            out.println(ansi.new Text(versionInfo));
-        }
-    }
-    /**
-     * Prints version information from the {@link Command#version()} annotation to the specified {@code PrintStream}.
-     * Each element of the array of version strings is {@linkplain String#format(String, Object...) formatted} with the
-     * specified parameters, and printed on a separate line. Both version strings and parameters may contain
-     * markup for colors and style .
-     * @param out the printStream to print to
-     * @param ansi whether the usage message should include ANSI escape codes or not
-     * @param params Arguments referenced by the format specifiers in the version strings
-     * @see Command#version()
-     * @see Option#versionHelp()
-     * @see #isVersionHelpRequested()
-     * @since 1.0.0
-     */
-    public void printVersionHelp(final PrintStream out, final Help.Ansi ansi, final Object... params) {
-        for (final String versionInfo : versionLines) {
-            out.println(ansi.new Text(String.format(versionInfo, params)));
-        }
-    }
-
-    /**
-     * Delegates to {@link #call(Callable, PrintStream, Help.Ansi, String...)} with {@link Help.Ansi#AUTO}.
-     * 
-     * From picocli v2.0, this method prints usage help or version help if {@linkplain #printHelpIfRequested(List, PrintStream, Help.Ansi) requested},
-     * and any exceptions thrown by the {@code Callable} are caught and rethrown wrapped in an {@code ExecutionException}.
-     * 
-     * @param callable the command to call when {@linkplain #parse(String...) parsing} succeeds.
-     * @param out the printStream to print to
-     * @param args the command line arguments to parse
-     * @param  the annotated object must implement Callable
-     * @param  the return type of the most specific command (must implement {@code Callable})
-     * @see #call(Callable, PrintStream, Help.Ansi, String...)
-     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
-     * @throws ExecutionException if the Callable throws an exception
-     * @return {@code null} if an error occurred while parsing the command line options, otherwise returns the result of calling the Callable
-     * @see #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...)
-     * @see RunFirst
-     */
-    public static , T> T call(final C callable, final PrintStream out, final String... args) {
-        return call(callable, out, Help.Ansi.AUTO, args);
-    }
-    /**
-     * Convenience method to allow command line application authors to avoid some boilerplate code in their application.
-     * The annotated object needs to implement {@link Callable}. Calling this method is equivalent to:
-     * 
-     * CommandLine cmd = new CommandLine(callable);
-     * List<CommandLine> parsedCommands;
-     * try {
-     *     parsedCommands = cmd.parse(args);
-     * } catch (ParameterException ex) {
-     *     out.println(ex.getMessage());
-     *     cmd.usage(out, ansi);
-     *     return null;
-     * }
-     * if (CommandLine.printHelpIfRequested(parsedCommands, out, ansi)) {
-     *     return null;
-     * }
-     * CommandLine last = parsedCommands.get(parsedCommands.size() - 1);
-     * try {
-     *     Callable<Object> subcommand = last.getCommand();
-     *     return subcommand.call();
-     * } catch (Exception ex) {
-     *     throw new ExecutionException(last, "Error calling " + last.getCommand(), ex);
-     * }
-     *  
-     * 
-     * If the specified Callable command has subcommands, the {@linkplain RunLast last} subcommand specified on the
-     * command line is executed.
-     * Commands with subcommands may be interested in calling the {@link #parseWithHandler(IParseResultHandler, PrintStream, String...) parseWithHandler}
-     * method with a {@link RunAll} handler or a custom handler.
-     * 
-     * From picocli v2.0, this method prints usage help or version help if {@linkplain #printHelpIfRequested(List, PrintStream, Help.Ansi) requested},
-     * and any exceptions thrown by the {@code Callable} are caught and rethrown wrapped in an {@code ExecutionException}.
-     * 
-     * @param callable the command to call when {@linkplain #parse(String...) parsing} succeeds.
-     * @param out the printStream to print to
-     * @param ansi whether the usage message should include ANSI escape codes or not
-     * @param args the command line arguments to parse
-     * @param  the annotated object must implement Callable
-     * @param  the return type of the specified {@code Callable}
-     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
-     * @throws ExecutionException if the Callable throws an exception
-     * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable
-     * @see #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...)
-     * @see RunLast
-     */
-    public static , T> T call(
-            final C callable, final PrintStream out, final Help.Ansi ansi, final String... args) {
-        final CommandLine cmd = new CommandLine(callable); // validate command outside of try-catch
-        final List results =
-                cmd.parseWithHandlers(new RunLast(), out, ansi, new DefaultExceptionHandler(), args);
-        return results == null || results.isEmpty() ? null : (T) results.get(0);
-    }
-
-    /**
-     * Delegates to {@link #run(Runnable, PrintStream, Help.Ansi, String...)} with {@link Help.Ansi#AUTO}.
-     * 
-     * From picocli v2.0, this method prints usage help or version help if {@linkplain #printHelpIfRequested(List, PrintStream, Help.Ansi) requested},
-     * and any exceptions thrown by the {@code Runnable} are caught and rethrown wrapped in an {@code ExecutionException}.
-     * 
-     * @param runnable the command to run when {@linkplain #parse(String...) parsing} succeeds.
-     * @param out the printStream to print to
-     * @param args the command line arguments to parse
-     * @param  the annotated object must implement Runnable
-     * @see #run(Runnable, PrintStream, Help.Ansi, String...)
-     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
-     * @throws ExecutionException if the Runnable throws an exception
-     * @see #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...)
-     * @see RunFirst
-     */
-    public static  void run(final R runnable, final PrintStream out, final String... args) {
-        run(runnable, out, Help.Ansi.AUTO, args);
-    }
-    /**
-     * Convenience method to allow command line application authors to avoid some boilerplate code in their application.
-     * The annotated object needs to implement {@link Runnable}. Calling this method is equivalent to:
-     * 
-     * CommandLine cmd = new CommandLine(runnable);
-     * List<CommandLine> parsedCommands;
-     * try {
-     *     parsedCommands = cmd.parse(args);
-     * } catch (ParameterException ex) {
-     *     out.println(ex.getMessage());
-     *     cmd.usage(out, ansi);
-     *     return null;
-     * }
-     * if (CommandLine.printHelpIfRequested(parsedCommands, out, ansi)) {
-     *     return null;
-     * }
-     * CommandLine last = parsedCommands.get(parsedCommands.size() - 1);
-     * try {
-     *     Runnable subcommand = last.getCommand();
-     *     subcommand.run();
-     * } catch (Exception ex) {
-     *     throw new ExecutionException(last, "Error running " + last.getCommand(), ex);
-     * }
-     *  
-     * 
-     * If the specified Runnable command has subcommands, the {@linkplain RunLast last} subcommand specified on the
-     * command line is executed.
-     * Commands with subcommands may be interested in calling the {@link #parseWithHandler(IParseResultHandler, PrintStream, String...) parseWithHandler}
-     * method with a {@link RunAll} handler or a custom handler.
-     * 
-     * From picocli v2.0, this method prints usage help or version help if {@linkplain #printHelpIfRequested(List, PrintStream, Help.Ansi) requested},
-     * and any exceptions thrown by the {@code Runnable} are caught and rethrown wrapped in an {@code ExecutionException}.
-     * 
-     * @param runnable the command to run when {@linkplain #parse(String...) parsing} succeeds.
-     * @param out the printStream to print to
-     * @param ansi whether the usage message should include ANSI escape codes or not
-     * @param args the command line arguments to parse
-     * @param  the annotated object must implement Runnable
-     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
-     * @throws ExecutionException if the Runnable throws an exception
-     * @see #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...)
-     * @see RunLast
-     */
-    public static  void run(
-            final R runnable, final PrintStream out, final Help.Ansi ansi, final String... args) {
-        final CommandLine cmd = new CommandLine(runnable); // validate command outside of try-catch
-        cmd.parseWithHandlers(new RunLast(), out, ansi, new DefaultExceptionHandler(), args);
-    }
-
-    /**
-     * Registers the specified type converter for the specified class. When initializing fields annotated with
-     * {@link Option}, the field's type is used as a lookup key to find the associated type converter, and this
-     * type converter converts the original command line argument string value to the correct type.
-     * 
-     * Java 8 lambdas make it easy to register custom type converters:
-     * 
-     * 
-     * commandLine.registerConverter(java.nio.file.Path.class, s -> java.nio.file.Paths.get(s));
-     * commandLine.registerConverter(java.time.Duration.class, s -> java.time.Duration.parse(s)); 
-     * 
-     * Built-in type converters are pre-registered for the following java 1.5 types:
-     * 
-     * 
-     *   all primitive types 
-     *   all primitive wrapper types: Boolean, Byte, Character, Double, Float, Integer, Long, Short 
-     *   any enum 
-     *   java.io.File 
-     *   java.math.BigDecimal 
-     *   java.math.BigInteger 
-     *   java.net.InetAddress 
-     *   java.net.URI 
-     *   java.net.URL 
-     *   java.nio.charset.Charset 
-     *   java.sql.Time 
-     *   java.util.Date 
-     *   java.util.UUID 
-     *   java.util.regex.Pattern 
-     *   StringBuilder 
-     *   CharSequence 
-     *   String 
-     *  
-     * The specified converter will be registered with this {@code CommandLine} and the full hierarchy of its
-     * subcommands and nested sub-subcommands at the moment the converter is registered . Subcommands added
-     * later will not have this converter added automatically. To ensure a custom type converter is available to all
-     * subcommands, register the type converter last, after adding subcommands.
-     *
-     * @param cls the target class to convert parameter string values to
-     * @param converter the class capable of converting string values to the specified target type
-     * @param  the target type
-     * @return this CommandLine object, to allow method chaining
-     * @see #addSubcommand(String, Object)
-     */
-    public  CommandLine registerConverter(final Class cls, final ITypeConverter converter) {
-        interpreter.converterRegistry.put(Assert.notNull(cls, "class"), Assert.notNull(converter, "converter"));
-        for (final CommandLine command : interpreter.commands.values()) {
-            command.registerConverter(cls, converter);
-        }
-        return this;
-    }
-
-    /** Returns the String that separates option names from option values when parsing command line options. {@value Help#DEFAULT_SEPARATOR} by default.
-     * @return the String the parser uses to separate option names from option values */
-    public String getSeparator() {
-        return interpreter.separator;
-    }
-
-    /** Sets the String the parser uses to separate option names from option values to the specified value.
-     * The separator may also be set declaratively with the {@link CommandLine.Command#separator()} annotation attribute.
-     * @param separator the String that separates option names from option values
-     * @return this {@code CommandLine} object, to allow method chaining */
-    public CommandLine setSeparator(final String separator) {
-        interpreter.separator = Assert.notNull(separator, "separator");
-        return this;
-    }
-
-    /** Returns the command name (also called program name) displayed in the usage help synopsis. {@value Help#DEFAULT_COMMAND_NAME} by default.
-     * @return the command name (also called program name) displayed in the usage */
-    public String getCommandName() {
-        return commandName;
-    }
-
-    /** Sets the command name (also called program name) displayed in the usage help synopsis to the specified value.
-     * Note that this method only modifies the usage help message, it does not impact parsing behaviour.
-     * The command name may also be set declaratively with the {@link CommandLine.Command#name()} annotation attribute.
-     * @param commandName command name (also called program name) displayed in the usage help synopsis
-     * @return this {@code CommandLine} object, to allow method chaining */
-    public CommandLine setCommandName(final String commandName) {
-        this.commandName = Assert.notNull(commandName, "commandName");
-        return this;
-    }
-
-    private static boolean empty(final String str) {
-        return str == null || str.trim().length() == 0;
-    }
-
-    private static boolean empty(final Object[] array) {
-        return array == null || array.length == 0;
-    }
-
-    private static boolean empty(final Text txt) {
-        return txt == null || txt.plain.toString().trim().length() == 0;
-    }
-
-    private static String str(final String[] arr, final int i) {
-        return (arr == null || arr.length == 0) ? "" : arr[i];
-    }
-
-    private static boolean isBoolean(final Class> type) {
-        return type == Boolean.class || type == Boolean.TYPE;
-    }
-
-    private static CommandLine toCommandLine(final Object obj) {
-        return obj instanceof CommandLine ? (CommandLine) obj : new CommandLine(obj);
-    }
-
-    private static boolean isMultiValue(final Field field) {
-        return isMultiValue(field.getType());
-    }
-
-    private static boolean isMultiValue(final Class> cls) {
-        return cls.isArray() || Collection.class.isAssignableFrom(cls) || Map.class.isAssignableFrom(cls);
-    }
-
-    private static Class>[] getTypeAttribute(final Field field) {
-        final Class>[] explicit = field.isAnnotationPresent(Parameters.class)
-                ? field.getAnnotation(Parameters.class).type()
-                : field.getAnnotation(Option.class).type();
-        if (explicit.length > 0) {
-            return explicit;
-        }
-        if (field.getType().isArray()) {
-            return new Class>[] {field.getType().getComponentType()};
-        }
-        if (isMultiValue(field)) {
-            final Type type = field.getGenericType(); // e.g. Map
-            if (type instanceof ParameterizedType) {
-                final ParameterizedType parameterizedType = (ParameterizedType) type;
-                final Type[] paramTypes = parameterizedType.getActualTypeArguments(); // e.g. ? extends Number
-                final Class>[] result = new Class>[paramTypes.length];
-                for (int i = 0; i < paramTypes.length; i++) {
-                    if (paramTypes[i] instanceof Class) {
-                        result[i] = (Class>) paramTypes[i];
-                        continue;
-                    } // e.g. Long
-                    if (paramTypes[i] instanceof WildcardType) { // e.g. ? extends Number
-                        final WildcardType wildcardType = (WildcardType) paramTypes[i];
-                        final Type[] lower = wildcardType.getLowerBounds(); // e.g. []
-                        if (lower.length > 0 && lower[0] instanceof Class) {
-                            result[i] = (Class>) lower[0];
-                            continue;
-                        }
-                        final Type[] upper = wildcardType.getUpperBounds(); // e.g. Number
-                        if (upper.length > 0 && upper[0] instanceof Class) {
-                            result[i] = (Class>) upper[0];
-                            continue;
-                        }
-                    }
-                    Arrays.fill(result, String.class);
-                    return result; // too convoluted generic type, giving up
-                }
-                return result; // we inferred all types from ParameterizedType
-            }
-            return new Class>[] {String.class, String.class}; // field is multi-value but not ParameterizedType
-        }
-        return new Class>[] {field.getType()}; // not a multi-value field
-    }
-    /**
-     * 
-     * Annotate fields in your class with {@code @Option} and picocli will initialize these fields when matching
-     * arguments are specified on the command line.
-     * 
-     * For example:
-     * 
-     * import static picocli.CommandLine.*;
-     *
-     * public class MyClass {
-     *     @Parameters(type = File.class, description = "Any number of input files")
-     *     private List<File> files = new ArrayList<File>();
-     *
-     *     @Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
-     *     private File outputFile;
-     *
-     *     @Option(names = { "-v", "--verbose"}, description = "Verbosely list files processed")
-     *     private boolean verbose;
-     *
-     *     @Option(names = { "-h", "--help", "-?", "-help"}, usageHelp = true, description = "Display this help and exit")
-     *     private boolean help;
-     *
-     *     @Option(names = { "-V", "--version"}, versionHelp = true, description = "Display version information and exit")
-     *     private boolean version;
-     * }
-     *  
-     * 
-     * A field cannot be annotated with both {@code @Parameters} and {@code @Option} or a
-     * {@code ParameterException} is thrown.
-     * 
-     */
-    @Retention(RetentionPolicy.RUNTIME)
-    @Target(ElementType.FIELD)
-    public @interface Option {
-        /**
-         * One or more option names. At least one option name is required.
-         * 
-         * Different environments have different conventions for naming options, but usually options have a prefix
-         * that sets them apart from parameters.
-         * Picocli supports all of the below styles. The default separator is {@code '='}, but this can be configured.
-         * 
-         * *nix 
-         * 
-         * In Unix and Linux, options have a short (single-character) name, a long name or both.
-         * Short options
-         * (POSIX
-         * style  are single-character and are preceded by the {@code '-'} character, e.g., {@code `-v'}.
-         * GNU-style  long
-         * (or mnemonic ) options start with two dashes in a row, e.g., {@code `--file'}.
-         * 
Picocli supports the POSIX convention that short options can be grouped, with the last option
-         * optionally taking a parameter, which may be attached to the option name or separated by a space or
-         * a {@code '='} character. The below examples are all equivalent:
-         * 
-         * -xvfFILE
-         * -xvf FILE
-         * -xvf=FILE
-         * -xv --file FILE
-         * -xv --file=FILE
-         * -x -v --file FILE
-         * -x -v --file=FILE
-         *  
-         * DOS 
-         * 
-         * DOS options mostly have upper case single-character names and start with a single slash {@code '/'} character.
-         * Option parameters are separated by a {@code ':'} character. Options cannot be grouped together but
-         * must be specified separately. For example:
-         * 
-         * DIR /S /A:D /T:C
-         *  
-         * PowerShell 
-         * 
-         * Windows PowerShell options generally are a word preceded by a single {@code '-'} character, e.g., {@code `-Help'}.
-         * Option parameters are separated by a space or by a {@code ':'} character.
-         * 
-         * @return one or more option names
-         */
-        String[] names();
-
-        /**
-         * Indicates whether this option is required. By default this is false.
-         * If an option is required, but a user invokes the program without specifying the required option,
-         * a {@link MissingParameterException} is thrown from the {@link #parse(String...)} method.
-         * @return whether this option is required
-         */
-        boolean required() default false;
-
-        /**
-         * Set {@code help=true} if this option should disable validation of the remaining arguments:
-         * If the {@code help} option is specified, no error message is generated for missing required options.
-         * 
-         * This attribute is useful for special options like help ({@code -h} and {@code --help} on unix,
-         * {@code -?} and {@code -Help} on Windows) or version ({@code -V} and {@code --version} on unix,
-         * {@code -Version} on Windows).
-         * 
-         * 
-         * Note that the {@link #parse(String...)} method will not print help documentation. It will only set
-         * the value of the annotated field. It is the responsibility of the caller to inspect the annotated fields
-         * and take the appropriate action.
-         * 
-         * @return whether this option disables validation of the other arguments
-         * @deprecated Use {@link #usageHelp()} and {@link #versionHelp()} instead. See {@link #printHelpIfRequested(List, PrintStream, CommandLine.Help.Ansi)}
-         */
-        boolean help() default false;
-
-        /**
-         * Set {@code usageHelp=true} if this option allows the user to request usage help. If this option is
-         * specified on the command line, picocli will not validate the remaining arguments (so no "missing required
-         * option" errors) and the {@link CommandLine#isUsageHelpRequested()} method will return {@code true}.
-         * 
-         * This attribute is useful for special options like help ({@code -h} and {@code --help} on unix,
-         * {@code -?} and {@code -Help} on Windows).
-         * 
-         * 
-         * Note that the {@link #parse(String...)} method will not print usage help documentation. It will only set
-         * the value of the annotated field. It is the responsibility of the caller to inspect the annotated fields
-         * and take the appropriate action.
-         * 
-         * @return whether this option allows the user to request usage help
-         * @since 0.9.8
-         */
-        boolean usageHelp() default false;
-
-        /**
-         * Set {@code versionHelp=true} if this option allows the user to request version information. If this option is
-         * specified on the command line, picocli will not validate the remaining arguments (so no "missing required
-         * option" errors) and the {@link CommandLine#isVersionHelpRequested()} method will return {@code true}.
-         * 
-         * This attribute is useful for special options like version ({@code -V} and {@code --version} on unix,
-         * {@code -Version} on Windows).
-         * 
-         * 
-         * Note that the {@link #parse(String...)} method will not print version information. It will only set
-         * the value of the annotated field. It is the responsibility of the caller to inspect the annotated fields
-         * and take the appropriate action.
-         * 
-         * @return whether this option allows the user to request version information
-         * @since 0.9.8
-         */
-        boolean versionHelp() default false;
-
-        /**
-         * Description of this option, used when generating the usage documentation.
-         * @return the description of this option
-         */
-        String[] description() default {};
-
-        /**
-         * Specifies the minimum number of required parameters and the maximum number of accepted parameters.
-         * If an option declares a positive arity, and the user specifies an insufficient number of parameters on the
-         * command line, a {@link MissingParameterException} is thrown by the {@link #parse(String...)} method.
-         * 
-         * In many cases picocli can deduce the number of required parameters from the field's type.
-         * By default, flags (boolean options) have arity zero,
-         * and single-valued type fields (String, int, Integer, double, Double, File, Date, etc) have arity one.
-         * Generally, fields with types that cannot hold multiple values can omit the {@code arity} attribute.
-         * 
-         * Fields used to capture options with arity two or higher should have a type that can hold multiple values,
-         * like arrays or Collections. See {@link #type()} for strongly-typed Collection fields.
-         * 
-         * For example, if an option has 2 required parameters and any number of optional parameters,
-         * specify {@code @Option(names = "-example", arity = "2..*")}.
-         * 
-         * A note on boolean options 
-         * 
-         * By default picocli does not expect boolean options (also called "flags" or "switches") to have a parameter.
-         * You can make a boolean option take a required parameter by annotating your field with {@code arity="1"}.
-         * For example: 
-         * @Option(names = "-v", arity = "1") boolean verbose; 
-         * 
-         * Because this boolean field is defined with arity 1, the user must specify either {@code  -v false}
-         * or {@code  -v true}
-         * on the command line, or a {@link MissingParameterException} is thrown by the {@link #parse(String...)}
-         * method.
-         *   
-         * To make the boolean parameter possible but optional, define the field with {@code arity = "0..1"}.
-         * For example: 
-         * @Option(names="-v", arity="0..1") boolean verbose; 
-         * This will accept any of the below without throwing an exception:
-         * 
-         * -v
-         * -v true
-         * -v false
-         *  
-         * @return how many arguments this option requires
-         */
-        String arity() default "";
-
-        /**
-         * Specify a {@code paramLabel} for the option parameter to be used in the usage help message. If omitted,
-         * picocli uses the field name in fish brackets ({@code '<'} and {@code '>'}) by default. Example:
-         * class Example {
-         *     @Option(names = {"-o", "--output"}, paramLabel="FILE", description="path of the output file")
-         *     private File out;
-         *     @Option(names = {"-j", "--jobs"}, arity="0..1", description="Allow N jobs at once; infinite jobs with no arg.")
-         *     private int maxJobs = -1;
-         * } 
-         * By default, the above gives a usage help message like the following:
-         * Usage: <main class> [OPTIONS]
-         * -o, --output FILE       path of the output file
-         * -j, --jobs [<maxJobs>]  Allow N jobs at once; infinite jobs with no arg.
-         *  
-         * @return name of the option parameter used in the usage help message
-         */
-        String paramLabel() default "";
-
-        /** 
-         * Optionally specify a {@code type} to control exactly what Class the option parameter should be converted
-         * to. This may be useful when the field type is an interface or an abstract class. For example, a field can
-         * be declared to have type {@code java.lang.Number}, and annotating {@code @Option(type=Short.class)}
-         * ensures that the option parameter value is converted to a {@code Short} before setting the field value.
-         * 
-         * For array fields whose component  type is an interface or abstract class, specify the concrete component  type.
-         * For example, a field with type {@code Number[]} may be annotated with {@code @Option(type=Short.class)}
-         * to ensure that option parameter values are converted to {@code Short} before adding an element to the array.
-         * 
-         * Picocli will use the {@link ITypeConverter} that is
-         * {@linkplain #registerConverter(Class, ITypeConverter) registered} for the specified type to convert
-         * the raw String values before modifying the field value.
-         * 
-         * Prior to 2.0, the {@code type} attribute was necessary for {@code Collection} and {@code Map} fields,
-         * but starting from 2.0 picocli will infer the component type from the generic type's type arguments.
-         * For example, for a field of type {@code Map} picocli will know the option parameter
-         * should be split up in key=value pairs, where the key should be converted to a {@code java.util.concurrent.TimeUnit}
-         * enum value, and the value should be converted to a {@code Long}. No {@code @Option(type=...)} type attribute
-         * is required for this. For generic types with wildcards, picocli will take the specified upper or lower bound
-         * as the Class to convert to, unless the {@code @Option} annotation specifies an explicit {@code type} attribute.
-         *  
-         * If the field type is a raw collection or a raw map, and you want it to contain other values than Strings,
-         * or if the generic type's type arguments are interfaces or abstract classes, you may
-         * specify a {@code type} attribute to control the Class that the option parameter should be converted to.
-         * @return the type(s) to convert the raw String values
-         */
-        Class>[] type() default {};
-
-        /**
-         * Specify a regular expression to use to split option parameter values before applying them to the field.
-         * All elements resulting from the split are added to the array or Collection. Ignored for single-value fields.
-         * @return a regular expression to split option parameter values or {@code ""} if the value should not be split
-         * @see String#split(String)
-         */
-        String split() default "";
-
-        /**
-         * Set {@code hidden=true} if this option should not be included in the usage documentation.
-         * @return whether this option should be excluded from the usage message
-         */
-        boolean hidden() default false;
-    }
-    /**
-     * 
-     * Fields annotated with {@code @Parameters} will be initialized with positional parameters. By specifying the
-     * {@link #index()} attribute you can pick which (or what range) of the positional parameters to apply. If no index
-     * is specified, the field will get all positional parameters (so it should be an array or a collection).
-     * 
-     * When parsing the command line arguments, picocli first tries to match arguments to {@link Option Options}.
-     * Positional parameters are the arguments that follow the options, or the arguments that follow a "--" (double
-     * dash) argument on the command line.
-     * 
-     * For example:
-     * 
-     * import static picocli.CommandLine.*;
-     *
-     * public class MyCalcParameters {
-     *     @Parameters(type = BigDecimal.class, description = "Any number of input numbers")
-     *     private List<BigDecimal> files = new ArrayList<BigDecimal>();
-     *
-     *     @Option(names = { "-h", "--help", "-?", "-help"}, help = true, description = "Display this help and exit")
-     *     private boolean help;
-     * }
-     *  
-     * A field cannot be annotated with both {@code @Parameters} and {@code @Option} or a {@code ParameterException}
-     * is thrown.
-     */
-    @Retention(RetentionPolicy.RUNTIME)
-    @Target(ElementType.FIELD)
-    public @interface Parameters {
-        /** Specify an index ("0", or "1", etc.) to pick which of the command line arguments should be assigned to this
-         * field. For array or Collection fields, you can also specify an index range ("0..3", or "2..*", etc.) to assign
-         * a subset of the command line arguments to this field. The default is "*", meaning all command line arguments.
-         * @return an index or range specifying which of the command line arguments should be assigned to this field
-         */
-        String index() default "*";
-
-        /** Description of the parameter(s), used when generating the usage documentation.
-         * @return the description of the parameter(s)
-         */
-        String[] description() default {};
-
-        /**
-         * Specifies the minimum number of required parameters and the maximum number of accepted parameters. If a
-         * positive arity is declared, and the user specifies an insufficient number of parameters on the command line,
-         * {@link MissingParameterException} is thrown by the {@link #parse(String...)} method.
-         * The default depends on the type of the parameter: booleans require no parameters, arrays and Collections
-         * accept zero to any number of parameters, and any other type accepts one parameter.
-         * @return the range of minimum and maximum parameters accepted by this command
-         */
-        String arity() default "";
-
-        /**
-         * Specify a {@code paramLabel} for the parameter to be used in the usage help message. If omitted,
-         * picocli uses the field name in fish brackets ({@code '<'} and {@code '>'}) by default. Example:
-         * class Example {
-         *     @Parameters(paramLabel="FILE", description="path of the input FILE(s)")
-         *     private File[] inputFiles;
-         * } 
-         * By default, the above gives a usage help message like the following:
-         * Usage: <main class> [FILE...]
-         * [FILE...]       path of the input FILE(s)
-         *  
-         * @return name of the positional parameter used in the usage help message
-         */
-        String paramLabel() default "";
-
-        /**
-         * 
-         * Optionally specify a {@code type} to control exactly what Class the positional parameter should be converted
-         * to. This may be useful when the field type is an interface or an abstract class. For example, a field can
-         * be declared to have type {@code java.lang.Number}, and annotating {@code @Parameters(type=Short.class)}
-         * ensures that the positional parameter value is converted to a {@code Short} before setting the field value.
-         * 
-         * For array fields whose component  type is an interface or abstract class, specify the concrete component  type.
-         * For example, a field with type {@code Number[]} may be annotated with {@code @Parameters(type=Short.class)}
-         * to ensure that positional parameter values are converted to {@code Short} before adding an element to the array.
-         * 
-         * Picocli will use the {@link ITypeConverter} that is
-         * {@linkplain #registerConverter(Class, ITypeConverter) registered} for the specified type to convert
-         * the raw String values before modifying the field value.
-         * 
-         * Prior to 2.0, the {@code type} attribute was necessary for {@code Collection} and {@code Map} fields,
-         * but starting from 2.0 picocli will infer the component type from the generic type's type arguments.
-         * For example, for a field of type {@code Map} picocli will know the positional parameter
-         * should be split up in key=value pairs, where the key should be converted to a {@code java.util.concurrent.TimeUnit}
-         * enum value, and the value should be converted to a {@code Long}. No {@code @Parameters(type=...)} type attribute
-         * is required for this. For generic types with wildcards, picocli will take the specified upper or lower bound
-         * as the Class to convert to, unless the {@code @Parameters} annotation specifies an explicit {@code type} attribute.
-         *  
-         * If the field type is a raw collection or a raw map, and you want it to contain other values than Strings,
-         * or if the generic type's type arguments are interfaces or abstract classes, you may
-         * specify a {@code type} attribute to control the Class that the positional parameter should be converted to.
-         * @return the type(s) to convert the raw String values
-         */
-        Class>[] type() default {};
-
-        /**
-         * Specify a regular expression to use to split positional parameter values before applying them to the field.
-         * All elements resulting from the split are added to the array or Collection. Ignored for single-value fields.
-         * @return a regular expression to split operand values or {@code ""} if the value should not be split
-         * @see String#split(String)
-         */
-        String split() default "";
-
-        /**
-         * Set {@code hidden=true} if this parameter should not be included in the usage message.
-         * @return whether this parameter should be excluded from the usage message
-         */
-        boolean hidden() default false;
-    }
-
-    /**
-     * 
Annotate your class with {@code @Command} when you want more control over the format of the generated help
-     * message.
-     * 
-     * @Command(name      = "Encrypt",
-     *        description = "Encrypt FILE(s), or standard input, to standard output or to the output file.",
-     *        footer      = "Copyright (c) 2017")
-     * public class Encrypt {
-     *     @Parameters(paramLabel = "FILE", type = File.class, description = "Any number of input files")
-     *     private List<File> files     = new ArrayList<File>();
-     *
-     *     @Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
-     *     private File outputFile;
-     * } 
-     * 
-     * The structure of a help message looks like this:
-     * 
-     *   [header] 
-     *   [synopsis]: {@code Usage:  [OPTIONS] [FILE...]}  
-     *   [description] 
-     *   [parameter list]: {@code      [FILE...]   Any number of input files} 
-     *   [option list]: {@code   -h, --help   prints this help message and exits} 
-     *   [footer] 
-     *   */
-    @Retention(RetentionPolicy.RUNTIME)
-    @Target({ElementType.TYPE, ElementType.LOCAL_VARIABLE, ElementType.PACKAGE})
-    public @interface Command {
-        /** Program name to show in the synopsis. If omitted, {@code ""} is used.
-         * For {@linkplain #subcommands() declaratively added} subcommands, this attribute is also used
-         * by the parser to recognize subcommands in the command line arguments.
-         * @return the program name to show in the synopsis
-         * @see Help#commandName */
-        String name() default "";
-
-        /** A list of classes to instantiate and register as subcommands. When registering subcommands declaratively
-         * like this, you don't need to call the {@link CommandLine#addSubcommand(String, Object)} method. For example, this:
-         * 
-         * @Command(subcommands = {
-         *         GitStatus.class,
-         *         GitCommit.class,
-         *         GitBranch.class })
-         * public class Git { ... }
-         *
-         * CommandLine commandLine = new CommandLine(new Git());
-         *   is equivalent to this:
-         * 
-         * // alternative: programmatically add subcommands.
-         * // NOTE: in this case there should be no `subcommands` attribute on the @Command annotation.
-         * @Command public class Git { ... }
-         *
-         * CommandLine commandLine = new CommandLine(new Git())
-         *         .addSubcommand("status",   new GitStatus())
-         *         .addSubcommand("commit",   new GitCommit())
-         *         .addSubcommand("branch",   new GitBranch());
-         *  
-         * @return the declaratively registered subcommands of this command, or an empty array if none
-         * @see CommandLine#addSubcommand(String, Object)
-         * @since 0.9.8
-         */
-        Class>[] subcommands() default {};
-
-        /** String that separates options from option parameters. Default is {@code "="}. Spaces are also accepted.
-         * @return the string that separates options from option parameters, used both when parsing and when generating usage help
-         * @see Help#separator
-         * @see CommandLine#setSeparator(String) */
-        String separator() default "=";
-
-        /** Version information for this command, to print to the console when the user specifies an
-         * {@linkplain Option#versionHelp() option} to request version help. This is not part of the usage help message.
-         *
-         * @return a string or an array of strings with version information about this command.
-         * @since 0.9.8
-         * @see CommandLine#printVersionHelp(PrintStream)
-         */
-        String[] version() default {};
-
-        /** Set the heading preceding the header section. May contain embedded {@linkplain java.util.Formatter format specifiers}.
-         * @return the heading preceding the header section
-         * @see Help#headerHeading(Object...)  */
-        String headerHeading() default "";
-
-        /** Optional summary description of the command, shown before the synopsis.
-         * @return summary description of the command
-         * @see Help#header
-         * @see Help#header(Object...)  */
-        String[] header() default {};
-
-        /** Set the heading preceding the synopsis text. May contain embedded
-         * {@linkplain java.util.Formatter format specifiers}. The default heading is {@code "Usage: "} (without a line
-         * break between the heading and the synopsis text).
-         * @return the heading preceding the synopsis text
-         * @see Help#synopsisHeading(Object...)  */
-        String synopsisHeading() default "Usage: ";
-
-        /** Specify {@code true} to generate an abbreviated synopsis like {@code " [OPTIONS] [PARAMETERS...]"}.
-         * By default, a detailed synopsis with individual option names and parameters is generated.
-         * @return whether the synopsis should be abbreviated
-         * @see Help#abbreviateSynopsis
-         * @see Help#abbreviatedSynopsis()
-         * @see Help#detailedSynopsis(Comparator, boolean) */
-        boolean abbreviateSynopsis() default false;
-
-        /** Specify one or more custom synopsis lines to display instead of an auto-generated synopsis.
-         * @return custom synopsis text to replace the auto-generated synopsis
-         * @see Help#customSynopsis
-         * @see Help#customSynopsis(Object...) */
-        String[] customSynopsis() default {};
-
-        /** Set the heading preceding the description section. May contain embedded {@linkplain java.util.Formatter format specifiers}.
-         * @return the heading preceding the description section
-         * @see Help#descriptionHeading(Object...)  */
-        String descriptionHeading() default "";
-
-        /** Optional text to display between the synopsis line(s) and the list of options.
-         * @return description of this command
-         * @see Help#description
-         * @see Help#description(Object...) */
-        String[] description() default {};
-
-        /** Set the heading preceding the parameters list. May contain embedded {@linkplain java.util.Formatter format specifiers}.
-         * @return the heading preceding the parameters list
-         * @see Help#parameterListHeading(Object...)  */
-        String parameterListHeading() default "";
-
-        /** Set the heading preceding the options list. May contain embedded {@linkplain java.util.Formatter format specifiers}.
-         * @return the heading preceding the options list
-         * @see Help#optionListHeading(Object...)  */
-        String optionListHeading() default "";
-
-        /** Specify {@code false} to show Options in declaration order. The default is to sort alphabetically.
-         * @return whether options should be shown in alphabetic order.
-         * @see Help#sortOptions */
-        boolean sortOptions() default true;
-
-        /** Prefix required options with this character in the options list. The default is no marker: the synopsis
-         * indicates which options and parameters are required.
-         * @return the character to show in the options list to mark required options
-         * @see Help#requiredOptionMarker */
-        char requiredOptionMarker() default ' ';
-
-        /** Specify {@code true} to show default values in the description column of the options list (except for
-         * boolean options). False by default.
-         * @return whether the default values for options and parameters should be shown in the description column
-         * @see Help#showDefaultValues */
-        boolean showDefaultValues() default false;
-
-        /** Set the heading preceding the subcommands list. May contain embedded {@linkplain java.util.Formatter format specifiers}.
-         * The default heading is {@code "Commands:%n"} (with a line break at the end).
-         * @return the heading preceding the subcommands list
-         * @see Help#commandListHeading(Object...)  */
-        String commandListHeading() default "Commands:%n";
-
-        /** Set the heading preceding the footer section. May contain embedded {@linkplain java.util.Formatter format specifiers}.
-         * @return the heading preceding the footer section
-         * @see Help#footerHeading(Object...)  */
-        String footerHeading() default "";
-
-        /** Optional text to display after the list of options.
-         * @return text to display after the list of options
-         * @see Help#footer
-         * @see Help#footer(Object...) */
-        String[] footer() default {};
-    }
-    /**
-     * 
-     * When parsing command line arguments and initializing
-     * fields annotated with {@link Option @Option} or {@link Parameters @Parameters},
-     * String values can be converted to any type for which a {@code ITypeConverter} is registered.
-     * 
-     * This interface defines the contract for classes that know how to convert a String into some domain object.
-     * Custom converters can be registered with the {@link #registerConverter(Class, ITypeConverter)} method.
-     * 
-     * Java 8 lambdas make it easy to register custom type converters:
-     * 
-     * 
-     * commandLine.registerConverter(java.nio.file.Path.class, s -> java.nio.file.Paths.get(s));
-     * commandLine.registerConverter(java.time.Duration.class, s -> java.time.Duration.parse(s)); 
-     * 
-     * Built-in type converters are pre-registered for the following java 1.5 types:
-     * 
-     * 
-     *   all primitive types 
-     *   all primitive wrapper types: Boolean, Byte, Character, Double, Float, Integer, Long, Short 
-     *   any enum 
-     *   java.io.File 
-     *   java.math.BigDecimal 
-     *   java.math.BigInteger 
-     *   java.net.InetAddress 
-     *   java.net.URI 
-     *   java.net.URL 
-     *   java.nio.charset.Charset 
-     *   java.sql.Time 
-     *   java.util.Date 
-     *   java.util.UUID 
-     *   java.util.regex.Pattern 
-     *   StringBuilder 
-     *   CharSequence 
-     *   String 
-     *  
-     * @param  the type of the object that is the result of the conversion
-     */
-    public interface ITypeConverter {
-        /**
-         * Converts the specified command line argument value to some domain object.
-         * @param value the command line argument String value
-         * @return the resulting domain object
-         * @throws Exception an exception detailing what went wrong during the conversion
-         */
-        K convert(String value) throws Exception;
-    }
-    /** Describes the number of parameters required and accepted by an option or a positional parameter.
-     * @since 0.9.7
-     */
-    public static class Range implements Comparable {
-        /** Required number of parameters for an option or positional parameter. */
-        public final int min;
-        /** Maximum accepted number of parameters for an option or positional parameter. */
-        public final int max;
-
-        public final boolean isVariable;
-        private final boolean isUnspecified;
-        private final String originalValue;
-
-        /** Constructs a new Range object with the specified parameters.
-         * @param min minimum number of required parameters
-         * @param max maximum number of allowed parameters (or Integer.MAX_VALUE if variable)
-         * @param variable {@code true} if any number or parameters is allowed, {@code false} otherwise
-         * @param unspecified {@code true} if no arity was specified on the option/parameter (value is based on type)
-         * @param originalValue the original value that was specified on the option or parameter
-         */
-        public Range(
-                final int min,
-                final int max,
-                final boolean variable,
-                final boolean unspecified,
-                final String originalValue) {
-            this.min = min;
-            this.max = max;
-            this.isVariable = variable;
-            this.isUnspecified = unspecified;
-            this.originalValue = originalValue;
-        }
-        /** Returns a new {@code Range} based on the {@link Option#arity()} annotation on the specified field,
-         * or the field type's default arity if no arity was specified.
-         * @param field the field whose Option annotation to inspect
-         * @return a new {@code Range} based on the Option arity annotation on the specified field */
-        public static Range optionArity(final Field field) {
-            return field.isAnnotationPresent(Option.class)
-                    ? adjustForType(
-                            Range.valueOf(field.getAnnotation(Option.class).arity()), field)
-                    : new Range(0, 0, false, true, "0");
-        }
-        /** Returns a new {@code Range} based on the {@link Parameters#arity()} annotation on the specified field,
-         * or the field type's default arity if no arity was specified.
-         * @param field the field whose Parameters annotation to inspect
-         * @return a new {@code Range} based on the Parameters arity annotation on the specified field */
-        public static Range parameterArity(final Field field) {
-            return field.isAnnotationPresent(Parameters.class)
-                    ? adjustForType(
-                            Range.valueOf(field.getAnnotation(Parameters.class).arity()), field)
-                    : new Range(0, 0, false, true, "0");
-        }
-        /** Returns a new {@code Range} based on the {@link Parameters#index()} annotation on the specified field.
-         * @param field the field whose Parameters annotation to inspect
-         * @return a new {@code Range} based on the Parameters index annotation on the specified field */
-        public static Range parameterIndex(final Field field) {
-            return field.isAnnotationPresent(Parameters.class)
-                    ? Range.valueOf(field.getAnnotation(Parameters.class).index())
-                    : new Range(0, 0, false, true, "0");
-        }
-
-        static Range adjustForType(final Range result, final Field field) {
-            return result.isUnspecified ? defaultArity(field) : result;
-        }
-        /** Returns the default arity {@code Range}: for {@link Option options} this is 0 for booleans and 1 for
-         * other types, for {@link Parameters parameters} booleans have arity 0, arrays or Collections have
-         * arity "0..*", and other types have arity 1.
-         * @param field the field whose default arity to return
-         * @return a new {@code Range} indicating the default arity of the specified field
-         * @since 2.0 */
-        public static Range defaultArity(final Field field) {
-            final Class> type = field.getType();
-            if (field.isAnnotationPresent(Option.class)) {
-                return defaultArity(type);
-            }
-            if (isMultiValue(type)) {
-                return Range.valueOf("0..1");
-            }
-            return Range.valueOf("1"); // for single-valued fields (incl. boolean positional parameters)
-        }
-        /** Returns the default arity {@code Range} for {@link Option options}: booleans have arity 0, other types have arity 1.
-         * @param type the type whose default arity to return
-         * @return a new {@code Range} indicating the default arity of the specified type */
-        public static Range defaultArity(final Class> type) {
-            return isBoolean(type) ? Range.valueOf("0") : Range.valueOf("1");
-        }
-
-        private int size() {
-            return 1 + max - min;
-        }
-
-        static Range parameterCapacity(final Field field) {
-            final Range arity = parameterArity(field);
-            if (!isMultiValue(field)) {
-                return arity;
-            }
-            final Range index = parameterIndex(field);
-            if (arity.max == 0) {
-                return arity;
-            }
-            if (index.size() == 1) {
-                return arity;
-            }
-            if (index.isVariable) {
-                return Range.valueOf(arity.min + "..*");
-            }
-            if (arity.size() == 1) {
-                return Range.valueOf(arity.min * index.size() + "");
-            }
-            if (arity.isVariable) {
-                return Range.valueOf(arity.min * index.size() + "..*");
-            }
-            return Range.valueOf(arity.min * index.size() + ".." + arity.max * index.size());
-        }
-        /** Leniently parses the specified String as an {@code Range} value and return the result. A range string can
-         * be a fixed integer value or a range of the form {@code MIN_VALUE + ".." + MAX_VALUE}. If the
-         * {@code MIN_VALUE} string is not numeric, the minimum is zero. If the {@code MAX_VALUE} is not numeric, the
-         * range is taken to be variable and the maximum is {@code Integer.MAX_VALUE}.
-         * @param range the value range string to parse
-         * @return a new {@code Range} value */
-        public static Range valueOf(String range) {
-            range = range.trim();
-            final boolean unspecified = range.length() == 0 || range.startsWith(".."); // || range.endsWith("..");
-            int min = -1, max = -1;
-            boolean variable = false;
-            int dots = -1;
-            if ((dots = range.indexOf("..")) >= 0) {
-                min = parseInt(range.substring(0, dots), 0);
-                max = parseInt(range.substring(dots + 2), Integer.MAX_VALUE);
-                variable = max == Integer.MAX_VALUE;
-            } else {
-                max = parseInt(range, Integer.MAX_VALUE);
-                variable = max == Integer.MAX_VALUE;
-                min = variable ? 0 : max;
-            }
-            return new Range(min, max, variable, unspecified, range);
-        }
-
-        private static int parseInt(final String str, final int defaultValue) {
-            try {
-                return Integer.parseInt(str);
-            } catch (final Exception ex) {
-                return defaultValue;
-            }
-        }
-        /** Returns a new Range object with the {@code min} value replaced by the specified value.
-         * The {@code max} of the returned Range is guaranteed not to be less than the new {@code min} value.
-         * @param newMin the {@code min} value of the returned Range object
-         * @return a new Range object with the specified {@code min} value */
-        public Range min(final int newMin) {
-            return new Range(newMin, Math.max(newMin, max), isVariable, isUnspecified, originalValue);
-        }
-
-        /** Returns a new Range object with the {@code max} value replaced by the specified value.
-         * The {@code min} of the returned Range is guaranteed not to be greater than the new {@code max} value.
-         * @param newMax the {@code max} value of the returned Range object
-         * @return a new Range object with the specified {@code max} value */
-        public Range max(final int newMax) {
-            return new Range(Math.min(min, newMax), newMax, isVariable, isUnspecified, originalValue);
-        }
-
-        /**
-         * Returns {@code true} if this Range includes the specified value, {@code false} otherwise.
-         * @param value the value to check
-         * @return {@code true} if the specified value is not less than the minimum and not greater than the maximum of this Range
-         */
-        public boolean contains(final int value) {
-            return min <= value && max >= value;
-        }
-
-        @Override
-        public boolean equals(final Object object) {
-            if (!(object instanceof Range)) {
-                return false;
-            }
-            final Range other = (Range) object;
-            return other.max == this.max && other.min == this.min && other.isVariable == this.isVariable;
-        }
-
-        @Override
-        public int hashCode() {
-            return ((17 * 37 + max) * 37 + min) * 37 + (isVariable ? 1 : 0);
-        }
-
-        @Override
-        public String toString() {
-            return min == max ? String.valueOf(min) : min + ".." + (isVariable ? "*" : max);
-        }
-
-        @Override
-        public int compareTo(final Range other) {
-            final int result = min - other.min;
-            return (result == 0) ? max - other.max : result;
-        }
-    }
-
-    static void init(
-            final Class> cls,
-            final List requiredFields,
-            final Map optionName2Field,
-            final Map singleCharOption2Field,
-            final List positionalParametersFields) {
-        final Field[] declaredFields = cls.getDeclaredFields();
-        for (final Field field : declaredFields) {
-            field.setAccessible(true);
-            if (field.isAnnotationPresent(Option.class)) {
-                final Option option = field.getAnnotation(Option.class);
-                if (option.required()) {
-                    requiredFields.add(field);
-                }
-                for (final String name : option.names()) { // cannot be null or empty
-                    final Field existing = optionName2Field.put(name, field);
-                    if (existing != null && existing != field) {
-                        throw DuplicateOptionAnnotationsException.create(name, field, existing);
-                    }
-                    if (name.length() == 2 && name.startsWith("-")) {
-                        final char flag = name.charAt(1);
-                        final Field existing2 = singleCharOption2Field.put(flag, field);
-                        if (existing2 != null && existing2 != field) {
-                            throw DuplicateOptionAnnotationsException.create(name, field, existing2);
-                        }
-                    }
-                }
-            }
-            if (field.isAnnotationPresent(Parameters.class)) {
-                if (field.isAnnotationPresent(Option.class)) {
-                    throw new DuplicateOptionAnnotationsException(
-                            "A field can be either @Option or @Parameters, but '" + field.getName() + "' is both.");
-                }
-                positionalParametersFields.add(field);
-                final Range arity = Range.parameterArity(field);
-                if (arity.min > 0) {
-                    requiredFields.add(field);
-                }
-            }
-        }
-    }
-
-    static void validatePositionalParameters(final List positionalParametersFields) {
-        int min = 0;
-        for (final Field field : positionalParametersFields) {
-            final Range index = Range.parameterIndex(field);
-            if (index.min > min) {
-                throw new ParameterIndexGapException("Missing field annotated with @Parameter(index=" + min
-                        + "). Nearest field '" + field.getName() + "' has index=" + index.min);
-            }
-            min = Math.max(min, index.max);
-            min = min == Integer.MAX_VALUE ? min : min + 1;
-        }
-    }
-
-    private static  Stack reverse(final Stack stack) {
-        Collections.reverse(stack);
-        return stack;
-    }
-    /**
-     * Helper class responsible for processing command line arguments.
-     */
-    private class Interpreter {
-        private final Map commands = new LinkedHashMap();
-        private final Map, ITypeConverter>> converterRegistry = new HashMap, ITypeConverter>>();
-        private final Map optionName2Field = new HashMap();
-        private final Map singleCharOption2Field = new HashMap();
-        private final List requiredFields = new ArrayList();
-        private final List positionalParametersFields = new ArrayList();
-        private final Object command;
-        private boolean isHelpRequested;
-        private String separator = Help.DEFAULT_SEPARATOR;
-        private int position;
-
-        Interpreter(final Object command) {
-            converterRegistry.put(Path.class, new BuiltIn.PathConverter());
-            converterRegistry.put(Object.class, new BuiltIn.StringConverter());
-            converterRegistry.put(String.class, new BuiltIn.StringConverter());
-            converterRegistry.put(StringBuilder.class, new BuiltIn.StringBuilderConverter());
-            converterRegistry.put(CharSequence.class, new BuiltIn.CharSequenceConverter());
-            converterRegistry.put(Byte.class, new BuiltIn.ByteConverter());
-            converterRegistry.put(Byte.TYPE, new BuiltIn.ByteConverter());
-            converterRegistry.put(Boolean.class, new BuiltIn.BooleanConverter());
-            converterRegistry.put(Boolean.TYPE, new BuiltIn.BooleanConverter());
-            converterRegistry.put(Character.class, new BuiltIn.CharacterConverter());
-            converterRegistry.put(Character.TYPE, new BuiltIn.CharacterConverter());
-            converterRegistry.put(Short.class, new BuiltIn.ShortConverter());
-            converterRegistry.put(Short.TYPE, new BuiltIn.ShortConverter());
-            converterRegistry.put(Integer.class, new BuiltIn.IntegerConverter());
-            converterRegistry.put(Integer.TYPE, new BuiltIn.IntegerConverter());
-            converterRegistry.put(Long.class, new BuiltIn.LongConverter());
-            converterRegistry.put(Long.TYPE, new BuiltIn.LongConverter());
-            converterRegistry.put(Float.class, new BuiltIn.FloatConverter());
-            converterRegistry.put(Float.TYPE, new BuiltIn.FloatConverter());
-            converterRegistry.put(Double.class, new BuiltIn.DoubleConverter());
-            converterRegistry.put(Double.TYPE, new BuiltIn.DoubleConverter());
-            converterRegistry.put(File.class, new BuiltIn.FileConverter());
-            converterRegistry.put(URI.class, new BuiltIn.URIConverter());
-            converterRegistry.put(URL.class, new BuiltIn.URLConverter());
-            converterRegistry.put(Date.class, new BuiltIn.ISO8601DateConverter());
-            converterRegistry.put(Time.class, new BuiltIn.ISO8601TimeConverter());
-            converterRegistry.put(BigDecimal.class, new BuiltIn.BigDecimalConverter());
-            converterRegistry.put(BigInteger.class, new BuiltIn.BigIntegerConverter());
-            converterRegistry.put(Charset.class, new BuiltIn.CharsetConverter());
-            converterRegistry.put(InetAddress.class, new BuiltIn.InetAddressConverter());
-            converterRegistry.put(Pattern.class, new BuiltIn.PatternConverter());
-            converterRegistry.put(UUID.class, new BuiltIn.UUIDConverter());
-
-            this.command = Assert.notNull(command, "command");
-            Class> cls = command.getClass();
-            String declaredName = null;
-            String declaredSeparator = null;
-            boolean hasCommandAnnotation = false;
-            while (cls != null) {
-                init(cls, requiredFields, optionName2Field, singleCharOption2Field, positionalParametersFields);
-                if (cls.isAnnotationPresent(Command.class)) {
-                    hasCommandAnnotation = true;
-                    final Command cmd = cls.getAnnotation(Command.class);
-                    declaredSeparator = (declaredSeparator == null) ? cmd.separator() : declaredSeparator;
-                    declaredName = (declaredName == null) ? cmd.name() : declaredName;
-                    CommandLine.this.versionLines.addAll(Arrays.asList(cmd.version()));
-
-                    for (final Class> sub : cmd.subcommands()) {
-                        final Command subCommand = sub.getAnnotation(Command.class);
-                        if (subCommand == null || Help.DEFAULT_COMMAND_NAME.equals(subCommand.name())) {
-                            throw new InitializationException("Subcommand " + sub.getName()
-                                    + " is missing the mandatory @Command annotation with a 'name' attribute");
-                        }
-                        try {
-                            final Constructor> constructor = sub.getDeclaredConstructor();
-                            constructor.setAccessible(true);
-                            final CommandLine commandLine = toCommandLine(constructor.newInstance());
-                            commandLine.parent = CommandLine.this;
-                            commands.put(subCommand.name(), commandLine);
-                        } catch (final InitializationException ex) {
-                            throw ex;
-                        } catch (final NoSuchMethodException ex) {
-                            throw new InitializationException(
-                                    "Cannot instantiate subcommand " + sub.getName() + ": the class has no constructor",
-                                    ex);
-                        } catch (final Exception ex) {
-                            throw new InitializationException(
-                                    "Could not instantiate and add subcommand " + sub.getName() + ": " + ex, ex);
-                        }
-                    }
-                }
-                cls = cls.getSuperclass();
-            }
-            separator = declaredSeparator != null ? declaredSeparator : separator;
-            CommandLine.this.commandName = declaredName != null ? declaredName : CommandLine.this.commandName;
-            Collections.sort(positionalParametersFields, new PositionalParametersSorter());
-            validatePositionalParameters(positionalParametersFields);
-
-            if (positionalParametersFields.isEmpty() && optionName2Field.isEmpty() && !hasCommandAnnotation) {
-                throw new InitializationException(command + " (" + command.getClass()
-                        + ") is not a command: it has no @Command, @Option or @Parameters annotations");
-            }
-        }
-
-        /**
-         * Entry point into parsing command line arguments.
-         * @param args the command line arguments
-         * @return a list with all commands and subcommands initialized by this method
-         * @throws ParameterException if the specified command line arguments are invalid
-         */
-        List parse(final String... args) {
-            Assert.notNull(args, "argument array");
-            if (tracer.isInfo()) {
-                tracer.info("Parsing %d command line args %s%n", args.length, Arrays.toString(args));
-            }
-            final Stack arguments = new Stack();
-            for (int i = args.length - 1; i >= 0; i--) {
-                arguments.push(args[i]);
-            }
-            final List result = new ArrayList();
-            parse(result, arguments, args);
-            return result;
-        }
-
-        private void parse(
-                final List parsedCommands,
-                final Stack argumentStack,
-                final String[] originalArgs) {
-            // first reset any state in case this CommandLine instance is being reused
-            isHelpRequested = false;
-            CommandLine.this.versionHelpRequested = false;
-            CommandLine.this.usageHelpRequested = false;
-
-            final Class> cmdClass = this.command.getClass();
-            if (tracer.isDebug()) {
-                tracer.debug(
-                        "Initializing %s: %d options, %d positional parameters, %d required, %d subcommands.%n",
-                        cmdClass.getName(),
-                        new HashSet(optionName2Field.values()).size(),
-                        positionalParametersFields.size(),
-                        requiredFields.size(),
-                        commands.size());
-            }
-            parsedCommands.add(CommandLine.this);
-            final List required = new ArrayList(requiredFields);
-            final Set initialized = new HashSet();
-            Collections.sort(required, new PositionalParametersSorter());
-            try {
-                processArguments(parsedCommands, argumentStack, required, initialized, originalArgs);
-            } catch (final ParameterException ex) {
-                throw ex;
-            } catch (final Exception ex) {
-                final int offendingArgIndex = originalArgs.length - argumentStack.size() - 1;
-                final String arg = offendingArgIndex >= 0 && offendingArgIndex < originalArgs.length
-                        ? originalArgs[offendingArgIndex]
-                        : "?";
-                throw ParameterException.create(CommandLine.this, ex, arg, offendingArgIndex, originalArgs);
-            }
-            if (!isAnyHelpRequested() && !required.isEmpty()) {
-                for (final Field missing : required) {
-                    if (missing.isAnnotationPresent(Option.class)) {
-                        throw MissingParameterException.create(CommandLine.this, required, separator);
-                    } else {
-                        assertNoMissingParameters(missing, Range.parameterArity(missing).min, argumentStack);
-                    }
-                }
-            }
-            if (!unmatchedArguments.isEmpty()) {
-                if (!isUnmatchedArgumentsAllowed()) {
-                    throw new UnmatchedArgumentException(CommandLine.this, unmatchedArguments);
-                }
-                if (tracer.isWarn()) {
-                    tracer.warn("Unmatched arguments: %s%n", unmatchedArguments);
-                }
-            }
-        }
-
-        private void processArguments(
-                final List parsedCommands,
-                final Stack args,
-                final Collection required,
-                final Set initialized,
-                final String[] originalArgs)
-                throws Exception {
-            // arg must be one of:
-            // 1. the "--" double dash separating options from positional arguments
-            // 1. a stand-alone flag, like "-v" or "--verbose": no value required, must map to boolean or Boolean field
-            // 2. a short option followed by an argument, like "-f file" or "-ffile": may map to any type of field
-            // 3. a long option followed by an argument, like "-file out.txt" or "-file=out.txt"
-            // 3. one or more remaining arguments without any associated options. Must be the last in the list.
-            // 4. a combination of stand-alone options, like "-vxr". Equivalent to "-v -x -r", "-v true -x true -r true"
-            // 5. a combination of stand-alone options and one option with an argument, like "-vxrffile"
-
-            while (!args.isEmpty()) {
-                String arg = args.pop();
-                if (tracer.isDebug()) {
-                    tracer.debug(
-                            "Processing argument '%s'. Remainder=%s%n", arg, reverse((Stack) args.clone()));
-                }
-
-                // Double-dash separates options from positional arguments.
-                // If found, then interpret the remaining args as positional parameters.
-                if ("--".equals(arg)) {
-                    tracer.info("Found end-of-options delimiter '--'. Treating remainder as positional parameters.%n");
-                    processRemainderAsPositionalParameters(required, initialized, args);
-                    return; // we are done
-                }
-
-                // if we find another command, we are done with the current command
-                if (commands.containsKey(arg)) {
-                    if (!isHelpRequested && !required.isEmpty()) { // ensure current command portion is valid
-                        throw MissingParameterException.create(CommandLine.this, required, separator);
-                    }
-                    if (tracer.isDebug()) {
-                        tracer.debug(
-                                "Found subcommand '%s' (%s)%n",
-                                arg,
-                                commands.get(arg).interpreter.command.getClass().getName());
-                    }
-                    commands.get(arg).interpreter.parse(parsedCommands, args, originalArgs);
-                    return; // remainder done by the command
-                }
-
-                // First try to interpret the argument as a single option (as opposed to a compact group of options).
-                // A single option may be without option parameters, like "-v" or "--verbose" (a boolean value),
-                // or an option may have one or more option parameters.
-                // A parameter may be attached to the option.
-                boolean paramAttachedToOption = false;
-                final int separatorIndex = arg.indexOf(separator);
-                if (separatorIndex > 0) {
-                    final String key = arg.substring(0, separatorIndex);
-                    // be greedy. Consume the whole arg as an option if possible.
-                    if (optionName2Field.containsKey(key) && !optionName2Field.containsKey(arg)) {
-                        paramAttachedToOption = true;
-                        final String optionParam = arg.substring(separatorIndex + separator.length());
-                        args.push(optionParam);
-                        arg = key;
-                        if (tracer.isDebug()) {
-                            tracer.debug("Separated '%s' option from '%s' option parameter%n", key, optionParam);
-                        }
-                    } else {
-                        if (tracer.isDebug()) {
-                            tracer.debug(
-                                    "'%s' contains separator '%s' but '%s' is not a known option%n",
-                                    arg, separator, key);
-                        }
-                    }
-                } else {
-                    if (tracer.isDebug()) {
-                        tracer.debug("'%s' cannot be separated into %s%n", arg, separator);
-                    }
-                }
-                if (optionName2Field.containsKey(arg)) {
-                    processStandaloneOption(required, initialized, arg, args, paramAttachedToOption);
-                }
-                // Compact (single-letter) options can be grouped with other options or with an argument.
-                // only single-letter options can be combined with other options or with an argument
-                else if (arg.length() > 2 && arg.startsWith("-")) {
-                    if (tracer.isDebug()) {
-                        tracer.debug("Trying to process '%s' as clustered short options%n", arg, args);
-                    }
-                    processClusteredShortOptions(required, initialized, arg, args);
-                }
-                // The argument could not be interpreted as an option.
-                // We take this to mean that the remainder are positional arguments
-                else {
-                    args.push(arg);
-                    if (tracer.isDebug()) {
-                        tracer.debug(
-                                "Could not find option '%s', deciding whether to treat as unmatched option or positional parameter...%n",
-                                arg);
-                    }
-                    if (resemblesOption(arg)) {
-                        handleUnmatchedArguments(args.pop());
-                        continue;
-                    } // #149
-                    if (tracer.isDebug()) {
-                        tracer.debug(
-                                "No option named '%s' found. Processing remainder as positional parameters%n", arg);
-                    }
-                    processPositionalParameter(required, initialized, args);
-                }
-            }
-        }
-
-        private boolean resemblesOption(final String arg) {
-            int count = 0;
-            for (final String optionName : optionName2Field.keySet()) {
-                for (int i = 0; i < arg.length(); i++) {
-                    if (optionName.length() > i && arg.charAt(i) == optionName.charAt(i)) {
-                        count++;
-                    } else {
-                        break;
-                    }
-                }
-            }
-            final boolean result = count > 0
-                    && count * 10
-                            >= optionName2Field.size()
-                                    * 9; // at least one prefix char in common with 9 out of 10 options
-            if (tracer.isDebug()) {
-                tracer.debug(
-                        "%s %s an option: %d matching prefix chars out of %d option names%n",
-                        arg, (result ? "resembles" : "doesn't resemble"), count, optionName2Field.size());
-            }
-            return result;
-        }
-
-        private void handleUnmatchedArguments(final String arg) {
-            final Stack args = new Stack();
-            args.add(arg);
-            handleUnmatchedArguments(args);
-        }
-
-        private void handleUnmatchedArguments(final Stack args) {
-            while (!args.isEmpty()) {
-                unmatchedArguments.add(args.pop());
-            } // addAll would give args in reverse order
-        }
-
-        private void processRemainderAsPositionalParameters(
-                final Collection required, final Set initialized, final Stack args)
-                throws Exception {
-            while (!args.empty()) {
-                processPositionalParameter(required, initialized, args);
-            }
-        }
-
-        private void processPositionalParameter(
-                final Collection required, final Set initialized, final Stack args)
-                throws Exception {
-            if (tracer.isDebug()) {
-                tracer.debug(
-                        "Processing next arg as a positional parameter at index=%d. Remainder=%s%n",
-                        position, reverse((Stack) args.clone()));
-            }
-            int consumed = 0;
-            for (final Field positionalParam : positionalParametersFields) {
-                final Range indexRange = Range.parameterIndex(positionalParam);
-                if (!indexRange.contains(position)) {
-                    continue;
-                }
-                @SuppressWarnings("unchecked")
-                final Stack argsCopy = (Stack) args.clone();
-                final Range arity = Range.parameterArity(positionalParam);
-                if (tracer.isDebug()) {
-                    tracer.debug(
-                            "Position %d is in index range %s. Trying to assign args to %s, arity=%s%n",
-                            position, indexRange, positionalParam, arity);
-                }
-                assertNoMissingParameters(positionalParam, arity.min, argsCopy);
-                final int originalSize = argsCopy.size();
-                applyOption(
-                        positionalParam,
-                        Parameters.class,
-                        arity,
-                        false,
-                        argsCopy,
-                        initialized,
-                        "args[" + indexRange + "] at position " + position);
-                final int count = originalSize - argsCopy.size();
-                if (count > 0) {
-                    required.remove(positionalParam);
-                }
-                consumed = Math.max(consumed, count);
-            }
-            // remove processed args from the stack
-            for (int i = 0; i < consumed; i++) {
-                args.pop();
-            }
-            position += consumed;
-            if (tracer.isDebug()) {
-                tracer.debug("Consumed %d arguments, moving position to index %d.%n", consumed, position);
-            }
-            if (consumed == 0 && !args.isEmpty()) {
-                handleUnmatchedArguments(args.pop());
-            }
-        }
-
-        private void processStandaloneOption(
-                final Collection required,
-                final Set initialized,
-                final String arg,
-                final Stack args,
-                final boolean paramAttachedToKey)
-                throws Exception {
-            final Field field = optionName2Field.get(arg);
-            required.remove(field);
-            Range arity = Range.optionArity(field);
-            if (paramAttachedToKey) {
-                arity = arity.min(Math.max(1, arity.min)); // if key=value, minimum arity is at least 1
-            }
-            if (tracer.isDebug()) {
-                tracer.debug("Found option named '%s': field %s, arity=%s%n", arg, field, arity);
-            }
-            applyOption(field, Option.class, arity, paramAttachedToKey, args, initialized, "option " + arg);
-        }
-
-        private void processClusteredShortOptions(
-                final Collection required,
-                final Set initialized,
-                final String arg,
-                final Stack args)
-                throws Exception {
-            final String prefix = arg.substring(0, 1);
-            String cluster = arg.substring(1);
-            boolean paramAttachedToOption = true;
-            do {
-                if (cluster.length() > 0 && singleCharOption2Field.containsKey(cluster.charAt(0))) {
-                    final Field field = singleCharOption2Field.get(cluster.charAt(0));
-                    Range arity = Range.optionArity(field);
-                    final String argDescription = "option " + prefix + cluster.charAt(0);
-                    if (tracer.isDebug()) {
-                        tracer.debug(
-                                "Found option '%s%s' in %s: field %s, arity=%s%n",
-                                prefix, cluster.charAt(0), arg, field, arity);
-                    }
-                    required.remove(field);
-                    cluster = cluster.length() > 0 ? cluster.substring(1) : "";
-                    paramAttachedToOption = cluster.length() > 0;
-                    if (cluster.startsWith(separator)) { // attached with separator, like -f=FILE or -v=true
-                        cluster = cluster.substring(separator.length());
-                        arity = arity.min(Math.max(1, arity.min)); // if key=value, minimum arity is at least 1
-                    }
-                    if (arity.min > 0 && !empty(cluster)) {
-                        if (tracer.isDebug()) {
-                            tracer.debug("Trying to process '%s' as option parameter%n", cluster);
-                        }
-                    }
-                    // arity may be >= 1, or
-                    // arity <= 0 && !cluster.startsWith(separator)
-                    // e.g., boolean @Option("-v", arity=0, varargs=true); arg "-rvTRUE", remainder cluster="TRUE"
-                    if (!empty(cluster)) {
-                        args.push(cluster); // interpret remainder as option parameter
-                    }
-                    final int consumed = applyOption(
-                            field, Option.class, arity, paramAttachedToOption, args, initialized, argDescription);
-                    // only return if cluster (and maybe more) was consumed, otherwise continue do-while loop
-                    if (empty(cluster) || consumed > 0 || args.isEmpty()) {
-                        return;
-                    }
-                    cluster = args.pop();
-                } else { // cluster is empty || cluster.charAt(0) is not a short option key
-                    if (cluster.length() == 0) { // we finished parsing a group of short options like -rxv
-                        return; // return normally and parse the next arg
-                    }
-                    // We get here when the remainder of the cluster group is neither an option,
-                    // nor a parameter that the last option could consume.
-                    if (arg.endsWith(cluster)) {
-                        args.push(paramAttachedToOption ? prefix + cluster : cluster);
-                        if (args.peek().equals(arg)) { // #149 be consistent between unmatched short and long options
-                            if (tracer.isDebug()) {
-                                tracer.debug(
-                                        "Could not match any short options in %s, deciding whether to treat as unmatched option or positional parameter...%n",
-                                        arg);
-                            }
-                            if (resemblesOption(arg)) {
-                                handleUnmatchedArguments(args.pop());
-                                return;
-                            } // #149
-                            processPositionalParameter(required, initialized, args);
-                            return;
-                        }
-                        // remainder was part of a clustered group that could not be completely parsed
-                        if (tracer.isDebug()) {
-                            tracer.debug("No option found for %s in %s%n", cluster, arg);
-                        }
-                        handleUnmatchedArguments(args.pop());
-                    } else {
-                        args.push(cluster);
-                        if (tracer.isDebug()) {
-                            tracer.debug("%s is not an option parameter for %s%n", cluster, arg);
-                        }
-                        processPositionalParameter(required, initialized, args);
-                    }
-                    return;
-                }
-            } while (true);
-        }
-
-        private int applyOption(
-                final Field field,
-                final Class> annotation,
-                final Range arity,
-                final boolean valueAttachedToOption,
-                final Stack args,
-                final Set initialized,
-                final String argDescription)
-                throws Exception {
-            updateHelpRequested(field);
-            final int length = args.size();
-            assertNoMissingParameters(field, arity.min, args);
-
-            Class> cls = field.getType();
-            if (cls.isArray()) {
-                return applyValuesToArrayField(field, annotation, arity, args, cls, argDescription);
-            }
-            if (Collection.class.isAssignableFrom(cls)) {
-                return applyValuesToCollectionField(field, annotation, arity, args, cls, argDescription);
-            }
-            if (Map.class.isAssignableFrom(cls)) {
-                return applyValuesToMapField(field, annotation, arity, args, cls, argDescription);
-            }
-            cls = getTypeAttribute(field)[
-                    0]; // field may be interface/abstract type, use annotation to get concrete type
-            return applyValueToSingleValuedField(field, arity, args, cls, initialized, argDescription);
-        }
-
-        private int applyValueToSingleValuedField(
-                final Field field,
-                final Range arity,
-                final Stack args,
-                final Class> cls,
-                final Set initialized,
-                final String argDescription)
-                throws Exception {
-            final boolean noMoreValues = args.isEmpty();
-            String value = args.isEmpty() ? null : trim(args.pop()); // unquote the value
-            int result = arity.min; // the number or args we need to consume
-
-            // special logic for booleans: BooleanConverter accepts only "true" or "false".
-            if ((cls == Boolean.class || cls == Boolean.TYPE) && arity.min <= 0) {
-
-                // boolean option with arity = 0..1 or 0..*: value MAY be a param
-                if (arity.max > 0 && ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value))) {
-                    result = 1; // if it is a varargs we only consume 1 argument if it is a boolean value
-                } else {
-                    if (value != null) {
-                        args.push(value); // we don't consume the value
-                    }
-                    final Boolean currentValue = (Boolean) field.get(command);
-                    value = String.valueOf(currentValue == null || !currentValue); // #147 toggle existing boolean value
-                }
-            }
-            if (noMoreValues && value == null) {
-                return 0;
-            }
-            final ITypeConverter> converter = getTypeConverter(cls, field);
-            final Object newValue = tryConvert(field, -1, converter, value, cls);
-            final Object oldValue = field.get(command);
-            TraceLevel level = TraceLevel.INFO;
-            String traceMessage = "Setting %s field '%s.%s' to '%5$s' (was '%4$s') for %6$s%n";
-            if (initialized != null) {
-                if (initialized.contains(field)) {
-                    if (!isOverwrittenOptionsAllowed()) {
-                        throw new OverwrittenOptionException(
-                                CommandLine.this, optionDescription("", field, 0) + " should be specified only once");
-                    }
-                    level = TraceLevel.WARN;
-                    traceMessage = "Overwriting %s field '%s.%s' value '%s' with '%s' for %s%n";
-                }
-                initialized.add(field);
-            }
-            if (tracer.level.isEnabled(level)) {
-                level.print(
-                        tracer,
-                        traceMessage,
-                        field.getType().getSimpleName(),
-                        field.getDeclaringClass().getSimpleName(),
-                        field.getName(),
-                        String.valueOf(oldValue),
-                        String.valueOf(newValue),
-                        argDescription);
-            }
-            field.set(command, newValue);
-            return result;
-        }
-
-        private int applyValuesToMapField(
-                final Field field,
-                final Class> annotation,
-                final Range arity,
-                final Stack args,
-                final Class> cls,
-                final String argDescription)
-                throws Exception {
-            final Class>[] classes = getTypeAttribute(field);
-            if (classes.length < 2) {
-                throw new ParameterException(
-                        CommandLine.this,
-                        "Field " + field + " needs two types (one for the map key, one for the value) but only has "
-                                + classes.length + " types configured.");
-            }
-            final ITypeConverter> keyConverter = getTypeConverter(classes[0], field);
-            final ITypeConverter> valueConverter = getTypeConverter(classes[1], field);
-            Map result = (Map) field.get(command);
-            if (result == null) {
-                result = createMap(cls);
-                field.set(command, result);
-            }
-            final int originalSize = result.size();
-            consumeMapArguments(field, arity, args, classes, keyConverter, valueConverter, result, argDescription);
-            return result.size() - originalSize;
-        }
-
-        private void consumeMapArguments(
-                final Field field,
-                final Range arity,
-                final Stack args,
-                final Class>[] classes,
-                final ITypeConverter> keyConverter,
-                final ITypeConverter> valueConverter,
-                final Map result,
-                final String argDescription)
-                throws Exception {
-            // first do the arity.min mandatory parameters
-            for (int i = 0; i < arity.min; i++) {
-                consumeOneMapArgument(
-                        field, arity, args, classes, keyConverter, valueConverter, result, i, argDescription);
-            }
-            // now process the varargs if any
-            for (int i = arity.min; i < arity.max && !args.isEmpty(); i++) {
-                if (!field.isAnnotationPresent(Parameters.class)) {
-                    if (commands.containsKey(args.peek()) || isOption(args.peek())) {
-                        return;
-                    }
-                }
-                consumeOneMapArgument(
-                        field, arity, args, classes, keyConverter, valueConverter, result, i, argDescription);
-            }
-        }
-
-        private void consumeOneMapArgument(
-                final Field field,
-                final Range arity,
-                final Stack args,
-                final Class>[] classes,
-                final ITypeConverter> keyConverter,
-                final ITypeConverter> valueConverter,
-                final Map result,
-                final int index,
-                final String argDescription)
-                throws Exception {
-            final String[] values = split(trim(args.pop()), field);
-            for (final String value : values) {
-                final String[] keyValue = value.split("=");
-                if (keyValue.length < 2) {
-                    final String splitRegex = splitRegex(field);
-                    if (splitRegex.length() == 0) {
-                        throw new ParameterException(
-                                CommandLine.this,
-                                "Value for option " + optionDescription("", field, 0)
-                                        + " should be in KEY=VALUE format but was " + value);
-                    } else {
-                        throw new ParameterException(
-                                CommandLine.this,
-                                "Value for option " + optionDescription("", field, 0) + " should be in KEY=VALUE["
-                                        + splitRegex + "KEY=VALUE]... format but was " + value);
-                    }
-                }
-                final Object mapKey = tryConvert(field, index, keyConverter, keyValue[0], classes[0]);
-                final Object mapValue = tryConvert(field, index, valueConverter, keyValue[1], classes[1]);
-                result.put(mapKey, mapValue);
-                if (tracer.isInfo()) {
-                    tracer.info(
-                            "Putting [%s : %s] in %s<%s, %s> field '%s.%s' for %s%n",
-                            String.valueOf(mapKey),
-                            String.valueOf(mapValue),
-                            result.getClass().getSimpleName(),
-                            classes[0].getSimpleName(),
-                            classes[1].getSimpleName(),
-                            field.getDeclaringClass().getSimpleName(),
-                            field.getName(),
-                            argDescription);
-                }
-            }
-        }
-
-        private void checkMaxArityExceeded(
-                final Range arity, final int remainder, final Field field, final String[] values) {
-            if (values.length <= remainder) {
-                return;
-            }
-            final String desc = arity.max == remainder ? "" + remainder : arity + ", remainder=" + remainder;
-            throw new MaxValuesforFieldExceededException(
-                    CommandLine.this,
-                    optionDescription("", field, -1) + " max number of values ("
-                            + arity.max + ") exceeded: remainder is " + remainder + " but " + values.length
-                            + " values were specified: " + Arrays.toString(values));
-        }
-
-        private int applyValuesToArrayField(
-                final Field field,
-                final Class> annotation,
-                final Range arity,
-                final Stack args,
-                final Class> cls,
-                final String argDescription)
-                throws Exception {
-            final Object existing = field.get(command);
-            final int length = existing == null ? 0 : Array.getLength(existing);
-            final Class> type = getTypeAttribute(field)[0];
-            final List converted =
-                    consumeArguments(field, annotation, arity, args, type, length, argDescription);
-            final List newValues = new ArrayList();
-            for (int i = 0; i < length; i++) {
-                newValues.add(Array.get(existing, i));
-            }
-            for (final Object obj : converted) {
-                if (obj instanceof Collection>) {
-                    newValues.addAll((Collection>) obj);
-                } else {
-                    newValues.add(obj);
-                }
-            }
-            final Object array = Array.newInstance(type, newValues.size());
-            field.set(command, array);
-            for (int i = 0; i < newValues.size(); i++) {
-                Array.set(array, i, newValues.get(i));
-            }
-            return converted.size(); // return how many args were consumed
-        }
-
-        @SuppressWarnings("unchecked")
-        private int applyValuesToCollectionField(
-                final Field field,
-                final Class> annotation,
-                final Range arity,
-                final Stack args,
-                final Class> cls,
-                final String argDescription)
-                throws Exception {
-            Collection collection = (Collection) field.get(command);
-            final Class> type = getTypeAttribute(field)[0];
-            final int length = collection == null ? 0 : collection.size();
-            final List converted =
-                    consumeArguments(field, annotation, arity, args, type, length, argDescription);
-            if (collection == null) {
-                collection = createCollection(cls);
-                field.set(command, collection);
-            }
-            for (final Object element : converted) {
-                if (element instanceof Collection>) {
-                    collection.addAll((Collection>) element);
-                } else {
-                    collection.add(element);
-                }
-            }
-            return converted.size();
-        }
-
-        private List consumeArguments(
-                final Field field,
-                final Class> annotation,
-                final Range arity,
-                final Stack args,
-                final Class> type,
-                final int originalSize,
-                final String argDescription)
-                throws Exception {
-            final List result = new ArrayList();
-
-            // first do the arity.min mandatory parameters
-            for (int i = 0; i < arity.min; i++) {
-                consumeOneArgument(field, arity, args, type, result, i, originalSize, argDescription);
-            }
-            // now process the varargs if any
-            for (int i = arity.min; i < arity.max && !args.isEmpty(); i++) {
-                if (annotation
-                        != Parameters
-                                .class) { // for vararg Options, we stop if we encounter '--', a command, or another
-                    // option
-                    if (commands.containsKey(args.peek()) || isOption(args.peek())) {
-                        return result;
-                    }
-                }
-                consumeOneArgument(field, arity, args, type, result, i, originalSize, argDescription);
-            }
-            return result;
-        }
-
-        private int consumeOneArgument(
-                final Field field,
-                final Range arity,
-                final Stack args,
-                final Class> type,
-                final List result,
-                int index,
-                final int originalSize,
-                final String argDescription)
-                throws Exception {
-            final String[] values = split(trim(args.pop()), field);
-            final ITypeConverter> converter = getTypeConverter(type, field);
-
-            for (int j = 0; j < values.length; j++) {
-                result.add(tryConvert(field, index, converter, values[j], type));
-                if (tracer.isInfo()) {
-                    if (field.getType().isArray()) {
-                        tracer.info(
-                                "Adding [%s] to %s[] field '%s.%s' for %s%n",
-                                String.valueOf(result.get(result.size() - 1)),
-                                type.getSimpleName(),
-                                field.getDeclaringClass().getSimpleName(),
-                                field.getName(),
-                                argDescription);
-                    } else {
-                        tracer.info(
-                                "Adding [%s] to %s<%s> field '%s.%s' for %s%n",
-                                String.valueOf(result.get(result.size() - 1)),
-                                field.getType().getSimpleName(),
-                                type.getSimpleName(),
-                                field.getDeclaringClass().getSimpleName(),
-                                field.getName(),
-                                argDescription);
-                    }
-                }
-            }
-            // checkMaxArityExceeded(arity, max, field, values);
-            return ++index;
-        }
-
-        private String splitRegex(final Field field) {
-            if (field.isAnnotationPresent(Option.class)) {
-                return field.getAnnotation(Option.class).split();
-            }
-            if (field.isAnnotationPresent(Parameters.class)) {
-                return field.getAnnotation(Parameters.class).split();
-            }
-            return "";
-        }
-
-        private String[] split(final String value, final Field field) {
-            final String regex = splitRegex(field);
-            return regex.length() == 0 ? new String[] {value} : value.split(regex);
-        }
-
-        /**
-         * Called when parsing varargs parameters for a multi-value option.
-         * When an option is encountered, the remainder should not be interpreted as vararg elements.
-         * @param arg the string to determine whether it is an option or not
-         * @return true if it is an option, false otherwise
-         */
-        private boolean isOption(final String arg) {
-            if ("--".equals(arg)) {
-                return true;
-            }
-            // not just arg prefix: we may be in the middle of parsing -xrvfFILE
-            if (optionName2Field.containsKey(arg)) { // -v or -f or --file (not attached to param or other option)
-                return true;
-            }
-            final int separatorIndex = arg.indexOf(separator);
-            if (separatorIndex > 0) { // -f=FILE or --file==FILE (attached to param via separator)
-                if (optionName2Field.containsKey(arg.substring(0, separatorIndex))) {
-                    return true;
-                }
-            }
-            return (arg.length() > 2 && arg.startsWith("-") && singleCharOption2Field.containsKey(arg.charAt(1)));
-        }
-
-        private Object tryConvert(
-                final Field field,
-                final int index,
-                final ITypeConverter> converter,
-                final String value,
-                final Class> type)
-                throws Exception {
-            try {
-                return converter.convert(value);
-            } catch (final TypeConversionException ex) {
-                throw new ParameterException(
-                        CommandLine.this, ex.getMessage() + optionDescription(" for ", field, index));
-            } catch (final Exception other) {
-                final String desc = optionDescription(" for ", field, index) + ": " + other;
-                throw new ParameterException(
-                        CommandLine.this, "Could not convert '" + value + "' to " + type.getSimpleName() + desc, other);
-            }
-        }
-
-        private String optionDescription(final String prefix, final Field field, final int index) {
-            final Help.IParamLabelRenderer labelRenderer = Help.createMinimalParamLabelRenderer();
-            String desc = "";
-            if (field.isAnnotationPresent(Option.class)) {
-                desc = prefix + "option '" + field.getAnnotation(Option.class).names()[0] + "'";
-                if (index >= 0) {
-                    final Range arity = Range.optionArity(field);
-                    if (arity.max > 1) {
-                        desc += " at index " + index;
-                    }
-                    desc += " ("
-                            + labelRenderer.renderParameterLabel(field, Help.Ansi.OFF, Collections.emptyList())
-                            + ")";
-                }
-            } else if (field.isAnnotationPresent(Parameters.class)) {
-                final Range indexRange = Range.parameterIndex(field);
-                final Text label =
-                        labelRenderer.renderParameterLabel(field, Help.Ansi.OFF, Collections.emptyList());
-                desc = prefix + "positional parameter at index " + indexRange + " (" + label + ")";
-            }
-            return desc;
-        }
-
-        private boolean isAnyHelpRequested() {
-            return isHelpRequested || versionHelpRequested || usageHelpRequested;
-        }
-
-        private void updateHelpRequested(final Field field) {
-            if (field.isAnnotationPresent(Option.class)) {
-                isHelpRequested |=
-                        is(field, "help", field.getAnnotation(Option.class).help());
-                CommandLine.this.versionHelpRequested |= is(
-                        field, "versionHelp", field.getAnnotation(Option.class).versionHelp());
-                CommandLine.this.usageHelpRequested |=
-                        is(field, "usageHelp", field.getAnnotation(Option.class).usageHelp());
-            }
-        }
-
-        private boolean is(final Field f, final String description, final boolean value) {
-            if (value) {
-                if (tracer.isInfo()) {
-                    tracer.info(
-                            "Field '%s.%s' has '%s' annotation: not validating required fields%n",
-                            f.getDeclaringClass().getSimpleName(), f.getName(), description);
-                }
-            }
-            return value;
-        }
-
-        @SuppressWarnings("unchecked")
-        private Collection createCollection(final Class> collectionClass) throws Exception {
-            if (collectionClass.isInterface()) {
-                if (List.class.isAssignableFrom(collectionClass)) {
-                    return new ArrayList();
-                } else if (SortedSet.class.isAssignableFrom(collectionClass)) {
-                    return new TreeSet();
-                } else if (Set.class.isAssignableFrom(collectionClass)) {
-                    return new LinkedHashSet();
-                } else if (Queue.class.isAssignableFrom(collectionClass)) {
-                    return new LinkedList(); // ArrayDeque is only available since 1.6
-                }
-                return new ArrayList();
-            }
-            // custom Collection implementation class must have default constructor
-            return (Collection) collectionClass.getDeclaredConstructor().newInstance();
-        }
-
-        private Map createMap(final Class> mapClass) throws Exception {
-            try { // if it is an implementation class, instantiate it
-                return (Map) mapClass.getDeclaredConstructor().newInstance();
-            } catch (final Exception ignored) {
-            }
-            return new LinkedHashMap();
-        }
-
-        private ITypeConverter> getTypeConverter(final Class> type, final Field field) {
-            final ITypeConverter> result = converterRegistry.get(type);
-            if (result != null) {
-                return result;
-            }
-            if (type.isEnum()) {
-                return (ITypeConverter) value -> Enum.valueOf((Class) type, value);
-            }
-            throw new MissingTypeConverterException(
-                    CommandLine.this, "No TypeConverter registered for " + type.getName() + " of field " + field);
-        }
-
-        private void assertNoMissingParameters(final Field field, final int arity, final Stack args) {
-            if (arity > args.size()) {
-                if (arity == 1) {
-                    if (field.isAnnotationPresent(Option.class)) {
-                        throw new MissingParameterException(
-                                CommandLine.this, "Missing required parameter for " + optionDescription("", field, 0));
-                    }
-                    final Range indexRange = Range.parameterIndex(field);
-                    final Help.IParamLabelRenderer labelRenderer = Help.createMinimalParamLabelRenderer();
-                    String sep = "";
-                    final StringBuilder names = new StringBuilder();
-                    int count = 0;
-                    for (int i = indexRange.min; i < positionalParametersFields.size(); i++) {
-                        if (Range.parameterArity(positionalParametersFields.get(i)).min > 0) {
-                            names.append(sep)
-                                    .append(labelRenderer.renderParameterLabel(
-                                            positionalParametersFields.get(i),
-                                            Help.Ansi.OFF,
-                                            Collections.emptyList()));
-                            sep = ", ";
-                            count++;
-                        }
-                    }
-                    String msg = "Missing required parameter";
-                    final Range paramArity = Range.parameterArity(field);
-                    if (paramArity.isVariable) {
-                        msg += "s at positions " + indexRange + ": ";
-                    } else {
-                        msg += (count > 1 ? "s: " : ": ");
-                    }
-                    throw new MissingParameterException(CommandLine.this, msg + names);
-                }
-                if (args.isEmpty()) {
-                    throw new MissingParameterException(
-                            CommandLine.this,
-                            optionDescription("", field, 0) + " requires at least " + arity
-                                    + " values, but none were specified.");
-                }
-                throw new MissingParameterException(
-                        CommandLine.this,
-                        optionDescription("", field, 0) + " requires at least " + arity + " values, but only "
-                                + args.size() + " were specified: " + reverse(args));
-            }
-        }
-
-        private String trim(final String value) {
-            return unquote(value);
-        }
-
-        private String unquote(final String value) {
-            return value == null
-                    ? null
-                    : (value.length() > 1 && value.startsWith("\"") && value.endsWith("\""))
-                            ? value.substring(1, value.length() - 1)
-                            : value;
-        }
-    }
-
-    private static class PositionalParametersSorter implements Comparator {
-        @Override
-        public int compare(final Field o1, final Field o2) {
-            final int result = Range.parameterIndex(o1).compareTo(Range.parameterIndex(o2));
-            return (result == 0) ? Range.parameterArity(o1).compareTo(Range.parameterArity(o2)) : result;
-        }
-    }
-
-    /**
-     * Inner class to group the built-in {@link ITypeConverter} implementations.
-     */
-    private static final class BuiltIn {
-        @SuppressFBWarnings("PATH_TRAVERSAL_IN")
-        static class PathConverter implements ITypeConverter {
-            @Override
-            public Path convert(final String value) {
-                return Paths.get(value);
-            }
-        }
-
-        static class StringConverter implements ITypeConverter {
-            @Override
-            public String convert(final String value) {
-                return value;
-            }
-        }
-
-        static class StringBuilderConverter implements ITypeConverter {
-            @Override
-            public StringBuilder convert(final String value) {
-                return new StringBuilder(value);
-            }
-        }
-
-        static class CharSequenceConverter implements ITypeConverter {
-            @Override
-            public String convert(final String value) {
-                return value;
-            }
-        }
-
-        /** Converts text to a {@code Byte} by delegating to {@link Byte#valueOf(String)}.*/
-        static class ByteConverter implements ITypeConverter {
-            @Override
-            public Byte convert(final String value) {
-                return Byte.valueOf(value);
-            }
-        }
-
-        /** Converts {@code "true"} or {@code "false"} to a {@code Boolean}. Other values result in a ParameterException.*/
-        static class BooleanConverter implements ITypeConverter {
-            @Override
-            public Boolean convert(final String value) {
-                if ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value)) {
-                    return Boolean.parseBoolean(value);
-                } else {
-                    throw new TypeConversionException("'" + value + "' is not a boolean");
-                }
-            }
-        }
-
-        static class CharacterConverter implements ITypeConverter {
-            @Override
-            public Character convert(final String value) {
-                if (value.length() > 1) {
-                    throw new TypeConversionException("'" + value + "' is not a single character");
-                }
-                return value.charAt(0);
-            }
-        }
-
-        /** Converts text to a {@code Short} by delegating to {@link Short#valueOf(String)}.*/
-        static class ShortConverter implements ITypeConverter {
-            @Override
-            public Short convert(final String value) {
-                return Short.valueOf(value);
-            }
-        }
-
-        /** Converts text to an {@code Integer} by delegating to {@link Integer#valueOf(String)}.*/
-        static class IntegerConverter implements ITypeConverter {
-            @Override
-            public Integer convert(final String value) {
-                return Integer.valueOf(value);
-            }
-        }
-
-        /** Converts text to a {@code Long} by delegating to {@link Long#valueOf(String)}.*/
-        static class LongConverter implements ITypeConverter {
-            @Override
-            public Long convert(final String value) {
-                return Long.valueOf(value);
-            }
-        }
-
-        static class FloatConverter implements ITypeConverter {
-            @Override
-            public Float convert(final String value) {
-                return Float.valueOf(value);
-            }
-        }
-
-        static class DoubleConverter implements ITypeConverter {
-            @Override
-            public Double convert(final String value) {
-                return Double.valueOf(value);
-            }
-        }
-
-        @SuppressFBWarnings("PATH_TRAVERSAL_IN")
-        static class FileConverter implements ITypeConverter {
-            @Override
-            public File convert(final String value) {
-                return new File(value);
-            }
-        }
-
-        static class URLConverter implements ITypeConverter {
-            @Override
-            public URL convert(final String value) throws MalformedURLException {
-                return new URL(value);
-            }
-        }
-
-        static class URIConverter implements ITypeConverter {
-            @Override
-            public URI convert(final String value) throws URISyntaxException {
-                return new URI(value);
-            }
-        }
-
-        /** Converts text in {@code yyyy-mm-dd} format to a {@code java.util.Date}. ParameterException on failure. */
-        static class ISO8601DateConverter implements ITypeConverter {
-            @Override
-            public Date convert(final String value) {
-                try {
-                    return new SimpleDateFormat("yyyy-MM-dd").parse(value);
-                } catch (final ParseException e) {
-                    throw new TypeConversionException("'" + value + "' is not a yyyy-MM-dd date");
-                }
-            }
-        }
-
-        /** Converts text in any of the following formats to a {@code java.sql.Time}: {@code HH:mm}, {@code HH:mm:ss},
-         * {@code HH:mm:ss.SSS}, {@code HH:mm:ss,SSS}. Other formats result in a ParameterException. */
-        static class ISO8601TimeConverter implements ITypeConverter {
-            @Override
-            public Time convert(final String value) {
-                try {
-                    if (value.length() <= 5) {
-                        return new Time(
-                                new SimpleDateFormat("HH:mm").parse(value).getTime());
-                    } else if (value.length() <= 8) {
-                        return new Time(
-                                new SimpleDateFormat("HH:mm:ss").parse(value).getTime());
-                    } else if (value.length() <= 12) {
-                        try {
-                            return new Time(new SimpleDateFormat("HH:mm:ss.SSS")
-                                    .parse(value)
-                                    .getTime());
-                        } catch (final ParseException e2) {
-                            return new Time(new SimpleDateFormat("HH:mm:ss,SSS")
-                                    .parse(value)
-                                    .getTime());
-                        }
-                    }
-                } catch (final ParseException ignored) {
-                    // ignored because we throw a ParameterException below
-                }
-                throw new TypeConversionException("'" + value + "' is not a HH:mm[:ss[.SSS]] time");
-            }
-        }
-
-        static class BigDecimalConverter implements ITypeConverter {
-            @Override
-            public BigDecimal convert(final String value) {
-                return new BigDecimal(value);
-            }
-        }
-
-        static class BigIntegerConverter implements ITypeConverter {
-            @Override
-            public BigInteger convert(final String value) {
-                return new BigInteger(value);
-            }
-        }
-
-        static class CharsetConverter implements ITypeConverter {
-            @Override
-            public Charset convert(final String s) {
-                return Charset.forName(s);
-            }
-        }
-
-        /** Converts text to a {@code InetAddress} by delegating to {@link InetAddress#getByName(String)}. */
-        static class InetAddressConverter implements ITypeConverter {
-            @Override
-            public InetAddress convert(final String s) throws Exception {
-                return InetAddress.getByName(s);
-            }
-        }
-
-        static class PatternConverter implements ITypeConverter {
-            @Override
-            public Pattern convert(final String s) {
-                return Pattern.compile(s);
-            }
-        }
-
-        static class UUIDConverter implements ITypeConverter {
-            @Override
-            public UUID convert(final String s) throws Exception {
-                return UUID.fromString(s);
-            }
-        }
-
-        private BuiltIn() {} // private constructor: never instantiate
-    }
-
-    /**
-     * A collection of methods and inner classes that provide fine-grained control over the contents and layout of
-     * the usage help message to display to end users when help is requested or invalid input values were specified.
-     * Layered API 
-     * The {@link Command} annotation provides the easiest way to customize usage help messages. See
-     * the Manual  for details.
-     * This Help class provides high-level functions to create sections of the usage help message and headings
-     * for these sections. Instead of calling the {@link CommandLine#usage(PrintStream, CommandLine.Help.ColorScheme)}
-     * method, application authors may want to create a custom usage help message by reorganizing sections in a
-     * different order and/or adding custom sections.
-     * Finally, the Help class contains inner classes and interfaces that can be used to create custom help messages.
-     * IOptionRenderer and IParameterRenderer 
-     * Renders a field annotated with {@link Option} or {@link Parameters} to an array of {@link Text} values.
-     * By default, these values are
-     * mandatory marker character (if the option/parameter is {@link Option#required() required}) 
-     * short option name (empty for parameters) 
-     * comma or empty (empty for parameters) 
-     * long option names (the parameter {@link IParamLabelRenderer label} for parameters) 
-     * description 
-     *  
-     * Other components rely on this ordering.
-     * Layout 
-     * Delegates to the renderers to create {@link Text} values for the annotated fields, and uses a
-     * {@link TextTable} to display these values in tabular format. Layout is responsible for deciding which values
-     * to display where in the table. By default, Layout shows one option or parameter per table row.
-     * TextTable 
-     * Responsible for spacing out {@link Text} values according to the {@link Column} definitions the table was
-     * created with. Columns have a width, indentation, and an overflow policy that decides what to do if a value is
-     * longer than the column's width.
-     * Text 
-     * Encapsulates rich text with styles and colors in a way that other components like {@link TextTable} are
-     * unaware of the embedded ANSI escape codes.
-     */
-    public static class Help {
-        /** Constant String holding the default program name: {@value} */
-        protected static final String DEFAULT_COMMAND_NAME = "";
-
-        /** Constant String holding the default string that separates options from option parameters: {@value} */
-        protected static final String DEFAULT_SEPARATOR = "=";
-
-        private static final int usageHelpWidth = 80;
-        private static final int optionsColumnWidth = 2 + 2 + 1 + 24;
-        private final Object command;
-        private final Map commands = new LinkedHashMap();
-        final ColorScheme colorScheme;
-
-        /** Immutable list of fields annotated with {@link Option}, in declaration order. */
-        public final List optionFields;
-
-        /** Immutable list of fields annotated with {@link Parameters}, or an empty list if no such field exists. */
-        public final List positionalParametersFields;
-
-        /** The String to use as the separator between options and option parameters. {@code "="} by default,
-         * initialized from {@link Command#separator()} if defined.
-         * @see #parameterLabelRenderer */
-        public String separator;
-
-        /** The String to use as the program name in the synopsis line of the help message.
-         * {@link #DEFAULT_COMMAND_NAME} by default, initialized from {@link Command#name()} if defined. */
-        public String commandName = DEFAULT_COMMAND_NAME;
-
-        /** Optional text lines to use as the description of the help message, displayed between the synopsis and the
-         * options list. Initialized from {@link Command#description()} if the {@code Command} annotation is present,
-         * otherwise this is an empty array and the help message has no description.
-         * Applications may programmatically set this field to create a custom help message. */
-        public String[] description = {};
-
-        /** Optional custom synopsis lines to use instead of the auto-generated synopsis.
-         * Initialized from {@link Command#customSynopsis()} if the {@code Command} annotation is present,
-         * otherwise this is an empty array and the synopsis is generated.
-         * Applications may programmatically set this field to create a custom help message. */
-        public String[] customSynopsis = {};
-
-        /** Optional header lines displayed at the top of the help message. For subcommands, the first header line is
-         * displayed in the list of commands. Values are initialized from {@link Command#header()}
-         * if the {@code Command} annotation is present, otherwise this is an empty array and the help message has no
-         * header. Applications may programmatically set this field to create a custom help message. */
-        public String[] header = {};
-
-        /** Optional footer text lines displayed at the bottom of the help message. Initialized from
-         * {@link Command#footer()} if the {@code Command} annotation is present, otherwise this is an empty array and
-         * the help message has no footer.
-         * Applications may programmatically set this field to create a custom help message. */
-        public String[] footer = {};
-
-        /** Option and positional parameter value label renderer used for the synopsis line(s) and the option list.
-         * By default initialized to the result of {@link #createDefaultParamLabelRenderer()}, which takes a snapshot
-         * of the {@link #separator} at construction time. If the separator is modified after Help construction, you
-         * may need to re-initialize this field by calling {@link #createDefaultParamLabelRenderer()} again. */
-        public IParamLabelRenderer parameterLabelRenderer;
-
-        /** If {@code true}, the synopsis line(s) will show an abbreviated synopsis without detailed option names. */
-        public Boolean abbreviateSynopsis;
-
-        /** If {@code true}, the options list is sorted alphabetically. */
-        public Boolean sortOptions;
-
-        /** If {@code true}, the options list will show default values for all options except booleans. */
-        public Boolean showDefaultValues;
-
-        /** Character used to prefix required options in the options list. */
-        public Character requiredOptionMarker;
-
-        /** Optional heading preceding the header section. Initialized from {@link Command#headerHeading()}, or null. */
-        public String headerHeading;
-
-        /** Optional heading preceding the synopsis. Initialized from {@link Command#synopsisHeading()}, {@code "Usage: "} by default. */
-        public String synopsisHeading;
-
-        /** Optional heading preceding the description section. Initialized from {@link Command#descriptionHeading()}, or null. */
-        public String descriptionHeading;
-
-        /** Optional heading preceding the parameter list. Initialized from {@link Command#parameterListHeading()}, or null. */
-        public String parameterListHeading;
-
-        /** Optional heading preceding the options list. Initialized from {@link Command#optionListHeading()}, or null. */
-        public String optionListHeading;
-
-        /** Optional heading preceding the subcommand list. Initialized from {@link Command#commandListHeading()}. {@code "Commands:%n"} by default. */
-        public String commandListHeading;
-
-        /** Optional heading preceding the footer section. Initialized from {@link Command#footerHeading()}, or null. */
-        public String footerHeading;
-
-        /** Constructs a new {@code Help} instance with a default color scheme, initialized from annotatations
-         * on the specified class and superclasses.
-         * @param command the annotated object to create usage help for */
-        public Help(final Object command) {
-            this(command, Ansi.AUTO);
-        }
-
-        /** Constructs a new {@code Help} instance with a default color scheme, initialized from annotatations
-         * on the specified class and superclasses.
-         * @param command the annotated object to create usage help for
-         * @param ansi whether to emit ANSI escape codes or not */
-        public Help(final Object command, final Ansi ansi) {
-            this(command, defaultColorScheme(ansi));
-        }
-
-        /** Constructs a new {@code Help} instance with the specified color scheme, initialized from annotatations
-         * on the specified class and superclasses.
-         * @param command the annotated object to create usage help for
-         * @param colorScheme the color scheme to use */
-        public Help(final Object command, final ColorScheme colorScheme) {
-            this.command = Assert.notNull(command, "command");
-            this.colorScheme = Assert.notNull(colorScheme, "colorScheme").applySystemProperties();
-            final List options = new ArrayList();
-            final List operands = new ArrayList();
-            Class> cls = command.getClass();
-            while (cls != null) {
-                for (final Field field : cls.getDeclaredFields()) {
-                    field.setAccessible(true);
-                    if (field.isAnnotationPresent(Option.class)) {
-                        final Option option = field.getAnnotation(Option.class);
-                        if (!option.hidden()) { // hidden options should not appear in usage help
-                            // TODO remember longest concatenated option string length (issue #45)
-                            options.add(field);
-                        }
-                    }
-                    if (field.isAnnotationPresent(Parameters.class)) {
-                        operands.add(field);
-                    }
-                }
-                // superclass values should not overwrite values if both class and superclass have a @Command annotation
-                if (cls.isAnnotationPresent(Command.class)) {
-                    final Command cmd = cls.getAnnotation(Command.class);
-                    if (DEFAULT_COMMAND_NAME.equals(commandName)) {
-                        commandName = cmd.name();
-                    }
-                    separator = (separator == null) ? cmd.separator() : separator;
-                    abbreviateSynopsis = (abbreviateSynopsis == null) ? cmd.abbreviateSynopsis() : abbreviateSynopsis;
-                    sortOptions = (sortOptions == null) ? cmd.sortOptions() : sortOptions;
-                    requiredOptionMarker =
-                            (requiredOptionMarker == null) ? cmd.requiredOptionMarker() : requiredOptionMarker;
-                    showDefaultValues = (showDefaultValues == null) ? cmd.showDefaultValues() : showDefaultValues;
-                    customSynopsis = empty(customSynopsis) ? cmd.customSynopsis() : customSynopsis;
-                    description = empty(description) ? cmd.description() : description;
-                    header = empty(header) ? cmd.header() : header;
-                    footer = empty(footer) ? cmd.footer() : footer;
-                    headerHeading = empty(headerHeading) ? cmd.headerHeading() : headerHeading;
-                    synopsisHeading = empty(synopsisHeading) || "Usage: ".equals(synopsisHeading)
-                            ? cmd.synopsisHeading()
-                            : synopsisHeading;
-                    descriptionHeading = empty(descriptionHeading) ? cmd.descriptionHeading() : descriptionHeading;
-                    parameterListHeading =
-                            empty(parameterListHeading) ? cmd.parameterListHeading() : parameterListHeading;
-                    optionListHeading = empty(optionListHeading) ? cmd.optionListHeading() : optionListHeading;
-                    commandListHeading = empty(commandListHeading) || "Commands:%n".equals(commandListHeading)
-                            ? cmd.commandListHeading()
-                            : commandListHeading;
-                    footerHeading = empty(footerHeading) ? cmd.footerHeading() : footerHeading;
-                }
-                cls = cls.getSuperclass();
-            }
-            sortOptions = sortOptions == null || sortOptions;
-            abbreviateSynopsis = abbreviateSynopsis != null && abbreviateSynopsis;
-            requiredOptionMarker = (requiredOptionMarker == null) ? ' ' : requiredOptionMarker;
-            showDefaultValues = showDefaultValues != null && showDefaultValues;
-            synopsisHeading = (synopsisHeading == null) ? "Usage: " : synopsisHeading;
-            commandListHeading = (commandListHeading == null) ? "Commands:%n" : commandListHeading;
-            separator = (separator == null) ? DEFAULT_SEPARATOR : separator;
-            parameterLabelRenderer = createDefaultParamLabelRenderer(); // uses help separator
-            Collections.sort(operands, new PositionalParametersSorter());
-            positionalParametersFields = Collections.unmodifiableList(operands);
-            optionFields = Collections.unmodifiableList(options);
-        }
-
-        /** Registers all specified subcommands with this Help.
-         * @param commands maps the command names to the associated CommandLine object
-         * @return this Help instance (for method chaining)
-         * @see CommandLine#getSubcommands()
-         */
-        public Help addAllSubcommands(final Map commands) {
-            if (commands != null) {
-                for (final Map.Entry entry : commands.entrySet()) {
-                    addSubcommand(entry.getKey(), entry.getValue().getCommand());
-                }
-            }
-            return this;
-        }
-
-        /** Registers the specified subcommand with this Help.
-         * @param commandName the name of the subcommand to display in the usage message
-         * @param command the annotated object to get more information from
-         * @return this Help instance (for method chaining)
-         */
-        public Help addSubcommand(final String commandName, final Object command) {
-            commands.put(commandName, new Help(command));
-            return this;
-        }
-
-        /** Returns a synopsis for the command without reserving space for the synopsis heading.
-         * @return a synopsis
-         * @see #abbreviatedSynopsis()
-         * @see #detailedSynopsis(Comparator, boolean)
-         * @deprecated use {@link #synopsis(int)} instead
-         */
-        @Deprecated
-        public String synopsis() {
-            return synopsis(0);
-        }
-
-        /**
-         * Returns a synopsis for the command, reserving the specified space for the synopsis heading.
-         * @param synopsisHeadingLength the length of the synopsis heading that will be displayed on the same line
-         * @return a synopsis
-         * @see #abbreviatedSynopsis()
-         * @see #detailedSynopsis(Comparator, boolean)
-         * @see #synopsisHeading
-         */
-        public String synopsis(final int synopsisHeadingLength) {
-            if (!empty(customSynopsis)) {
-                return customSynopsis();
-            }
-            return abbreviateSynopsis
-                    ? abbreviatedSynopsis()
-                    : detailedSynopsis(synopsisHeadingLength, createShortOptionArityAndNameComparator(), true);
-        }
-
-        /** Generates a generic synopsis like {@code  [OPTIONS] [PARAM1 [PARAM2]...]}, omitting parts
-         * that don't apply to the command (e.g., does not show [OPTIONS] if the command has no options).
-         * @return a generic synopsis */
-        public String abbreviatedSynopsis() {
-            final StringBuilder sb = new StringBuilder();
-            if (!optionFields.isEmpty()) { // only show if annotated object actually has options
-                sb.append(" [OPTIONS]");
-            }
-            // sb.append(" [--] "); // implied
-            for (final Field positionalParam : positionalParametersFields) {
-                if (!positionalParam.getAnnotation(Parameters.class).hidden()) {
-                    sb.append(' ')
-                            .append(parameterLabelRenderer.renderParameterLabel(
-                                    positionalParam, ansi(), colorScheme.parameterStyles));
-                }
-            }
-            return colorScheme.commandText(commandName).toString()
-                    + (sb.toString())
-                    + System.getProperty("line.separator");
-        }
-        /** Generates a detailed synopsis message showing all options and parameters. Follows the unix convention of
-         * showing optional options and parameters in square brackets ({@code [ ]}).
-         * @param optionSort comparator to sort options or {@code null} if options should not be sorted
-         * @param clusterBooleanOptions {@code true} if boolean short options should be clustered into a single string
-         * @return a detailed synopsis
-         * @deprecated use {@link #detailedSynopsis(int, Comparator, boolean)} instead. */
-        @Deprecated
-        public String detailedSynopsis(final Comparator optionSort, final boolean clusterBooleanOptions) {
-            return detailedSynopsis(0, optionSort, clusterBooleanOptions);
-        }
-
-        /** Generates a detailed synopsis message showing all options and parameters. Follows the unix convention of
-         * showing optional options and parameters in square brackets ({@code [ ]}).
-         * @param synopsisHeadingLength the length of the synopsis heading that will be displayed on the same line
-         * @param optionSort comparator to sort options or {@code null} if options should not be sorted
-         * @param clusterBooleanOptions {@code true} if boolean short options should be clustered into a single string
-         * @return a detailed synopsis */
-        public String detailedSynopsis(
-                final int synopsisHeadingLength,
-                final Comparator optionSort,
-                final boolean clusterBooleanOptions) {
-            Text optionText = ansi().new Text(0);
-            final List fields = new ArrayList(optionFields); // iterate in declaration order
-            if (optionSort != null) {
-                Collections.sort(fields, optionSort); // iterate in specified sort order
-            }
-            if (clusterBooleanOptions) { // cluster all short boolean options into a single string
-                final List booleanOptions = new ArrayList();
-                final StringBuilder clusteredRequired = new StringBuilder("-");
-                final StringBuilder clusteredOptional = new StringBuilder("-");
-                for (final Field field : fields) {
-                    if (field.getType() == boolean.class || field.getType() == Boolean.class) {
-                        final Option option = field.getAnnotation(Option.class);
-                        final String shortestName = ShortestFirst.sort(option.names())[0];
-                        if (shortestName.length() == 2 && shortestName.startsWith("-")) {
-                            booleanOptions.add(field);
-                            if (option.required()) {
-                                clusteredRequired.append(shortestName.substring(1));
-                            } else {
-                                clusteredOptional.append(shortestName.substring(1));
-                            }
-                        }
-                    }
-                }
-                fields.removeAll(booleanOptions);
-                if (clusteredRequired.length() > 1) { // initial length was 1
-                    optionText = optionText.append(" ").append(colorScheme.optionText(clusteredRequired.toString()));
-                }
-                if (clusteredOptional.length() > 1) { // initial length was 1
-                    optionText = optionText
-                            .append(" [")
-                            .append(colorScheme.optionText(clusteredOptional.toString()))
-                            .append("]");
-                }
-            }
-            for (final Field field : fields) {
-                final Option option = field.getAnnotation(Option.class);
-                if (!option.hidden()) {
-                    if (option.required()) {
-                        optionText =
-                                appendOptionSynopsis(optionText, field, ShortestFirst.sort(option.names())[0], " ", "");
-                        if (isMultiValue(field)) {
-                            optionText = appendOptionSynopsis(
-                                    optionText, field, ShortestFirst.sort(option.names())[0], " [", "]...");
-                        }
-                    } else {
-                        optionText = appendOptionSynopsis(
-                                optionText, field, ShortestFirst.sort(option.names())[0], " [", "]");
-                        if (isMultiValue(field)) {
-                            optionText = optionText.append("...");
-                        }
-                    }
-                }
-            }
-            for (final Field positionalParam : positionalParametersFields) {
-                if (!positionalParam.getAnnotation(Parameters.class).hidden()) {
-                    optionText = optionText.append(" ");
-                    final Text label = parameterLabelRenderer.renderParameterLabel(
-                            positionalParam, colorScheme.ansi(), colorScheme.parameterStyles);
-                    optionText = optionText.append(label);
-                }
-            }
-            // Fix for #142: first line of synopsis overshoots max. characters
-            final int firstColumnLength = commandName.length() + synopsisHeadingLength;
-
-            // synopsis heading ("Usage: ") may be on the same line, so adjust column width
-            final TextTable textTable = new TextTable(ansi(), firstColumnLength, usageHelpWidth - firstColumnLength);
-            textTable.indentWrappedLines =
-                    1; // don't worry about first line: options (2nd column) always start with a space
-
-            // right-adjust the command name by length of synopsis heading
-            final Text PADDING = Ansi.OFF.new Text(stringOf('X', synopsisHeadingLength));
-            textTable.addRowValues(new Text[] {PADDING.append(colorScheme.commandText(commandName)), optionText});
-            return textTable.toString().substring(synopsisHeadingLength); // cut off leading synopsis heading spaces
-        }
-
-        private Text appendOptionSynopsis(
-                final Text optionText,
-                final Field field,
-                final String optionName,
-                final String prefix,
-                final String suffix) {
-            final Text optionParamText = parameterLabelRenderer.renderParameterLabel(
-                    field, colorScheme.ansi(), colorScheme.optionParamStyles);
-            return optionText
-                    .append(prefix)
-                    .append(colorScheme.optionText(optionName))
-                    .append(optionParamText)
-                    .append(suffix);
-        }
-
-        /** Returns the number of characters the synopsis heading will take on the same line as the synopsis.
-         * @return the number of characters the synopsis heading will take on the same line as the synopsis.
-         * @see #detailedSynopsis(int, Comparator, boolean)
-         */
-        public int synopsisHeadingLength() {
-            final String[] lines = Ansi.OFF.new Text(synopsisHeading).toString().split("\\r?\\n|\\r|%n", -1);
-            return lines[lines.length - 1].length();
-        }
-        /**
-         * Returns a description of the {@linkplain Option options} supported by the application.
-         * This implementation {@linkplain #createShortOptionNameComparator() sorts options alphabetically}, and shows
-         * only the {@linkplain Option#hidden() non-hidden} options in a {@linkplain TextTable tabular format}
-         * using the {@linkplain #createDefaultOptionRenderer() default renderer} and {@linkplain Layout default layout}.
-         * @return the fully formatted option list
-         * @see #optionList(Layout, Comparator, IParamLabelRenderer)
-         */
-        public String optionList() {
-            final Comparator sortOrder =
-                    sortOptions == null || sortOptions.booleanValue() ? createShortOptionNameComparator() : null;
-            return optionList(createDefaultLayout(), sortOrder, parameterLabelRenderer);
-        }
-
-        /** Sorts all {@code Options} with the specified {@code comparator} (if the comparator is non-{@code null}),
-         * then {@linkplain Layout#addOption(Field, CommandLine.Help.IParamLabelRenderer) adds} all non-hidden options to the
-         * specified TextTable and returns the result of TextTable.toString().
-         * @param layout responsible for rendering the option list
-         * @param optionSort determines in what order {@code Options} should be listed. Declared order if {@code null}
-         * @param valueLabelRenderer used for options with a parameter
-         * @return the fully formatted option list
-         */
-        public String optionList(
-                final Layout layout, final Comparator optionSort, final IParamLabelRenderer valueLabelRenderer) {
-            final List fields = new ArrayList(optionFields); // options are stored in order of declaration
-            if (optionSort != null) {
-                Collections.sort(fields, optionSort); // default: sort options ABC
-            }
-            layout.addOptions(fields, valueLabelRenderer);
-            return layout.toString();
-        }
-
-        /**
-         * Returns the section of the usage help message that lists the parameters with their descriptions.
-         * @return the section of the usage help message that lists the parameters
-         */
-        public String parameterList() {
-            return parameterList(createDefaultLayout(), parameterLabelRenderer);
-        }
-        /**
-         * Returns the section of the usage help message that lists the parameters with their descriptions.
-         * @param layout the layout to use
-         * @param paramLabelRenderer for rendering parameter names
-         * @return the section of the usage help message that lists the parameters
-         */
-        public String parameterList(final Layout layout, final IParamLabelRenderer paramLabelRenderer) {
-            layout.addPositionalParameters(positionalParametersFields, paramLabelRenderer);
-            return layout.toString();
-        }
-
-        private static String heading(final Ansi ansi, final String values, final Object... params) {
-            final StringBuilder sb = join(ansi, new String[] {values}, new StringBuilder(), params);
-            String result = sb.toString();
-            result = result.endsWith(System.getProperty("line.separator"))
-                    ? result.substring(
-                            0,
-                            result.length()
-                                    - System.getProperty("line.separator").length())
-                    : result;
-            return result + new String(spaces(countTrailingSpaces(values)));
-        }
-
-        private static char[] spaces(final int length) {
-            final char[] result = new char[length];
-            Arrays.fill(result, ' ');
-            return result;
-        }
-
-        private static int countTrailingSpaces(final String str) {
-            if (str == null) {
-                return 0;
-            }
-            int trailingSpaces = 0;
-            for (int i = str.length() - 1; i >= 0 && str.charAt(i) == ' '; i--) {
-                trailingSpaces++;
-            }
-            return trailingSpaces;
-        }
-
-        /** Formats each of the specified values and appends it to the specified StringBuilder.
-         * @param ansi whether the result should contain ANSI escape codes or not
-         * @param values the values to format and append to the StringBuilder
-         * @param sb the StringBuilder to collect the formatted strings
-         * @param params the parameters to pass to the format method when formatting each value
-         * @return the specified StringBuilder */
-        public static StringBuilder join(
-                final Ansi ansi, final String[] values, final StringBuilder sb, final Object... params) {
-            if (values != null) {
-                final TextTable table = new TextTable(ansi, usageHelpWidth);
-                table.indentWrappedLines = 0;
-                for (final String summaryLine : values) {
-                    final Text[] lines = ansi.new Text(format(summaryLine, params)).splitLines();
-                    for (final Text line : lines) {
-                        table.addRowValues(line);
-                    }
-                }
-                table.toString(sb);
-            }
-            return sb;
-        }
-
-        private static String format(final String formatString, final Object... params) {
-            return formatString == null ? "" : String.format(formatString, params);
-        }
-        /** Returns command custom synopsis as a string. A custom synopsis can be zero or more lines, and can be
-         * specified declaratively with the {@link Command#customSynopsis()} annotation attribute or programmatically
-         * by setting the Help instance's {@link Help#customSynopsis} field.
-         * @param params Arguments referenced by the format specifiers in the synopsis strings
-         * @return the custom synopsis lines combined into a single String (which may be empty)
-         */
-        public String customSynopsis(final Object... params) {
-            return join(ansi(), customSynopsis, new StringBuilder(), params).toString();
-        }
-        /** Returns command description text as a string. Description text can be zero or more lines, and can be specified
-         * declaratively with the {@link Command#description()} annotation attribute or programmatically by
-         * setting the Help instance's {@link Help#description} field.
-         * @param params Arguments referenced by the format specifiers in the description strings
-         * @return the description lines combined into a single String (which may be empty)
-         */
-        public String description(final Object... params) {
-            return join(ansi(), description, new StringBuilder(), params).toString();
-        }
-        /** Returns the command header text as a string. Header text can be zero or more lines, and can be specified
-         * declaratively with the {@link Command#header()} annotation attribute or programmatically by
-         * setting the Help instance's {@link Help#header} field.
-         * @param params Arguments referenced by the format specifiers in the header strings
-         * @return the header lines combined into a single String (which may be empty)
-         */
-        public String header(final Object... params) {
-            return join(ansi(), header, new StringBuilder(), params).toString();
-        }
-        /** Returns command footer text as a string. Footer text can be zero or more lines, and can be specified
-         * declaratively with the {@link Command#footer()} annotation attribute or programmatically by
-         * setting the Help instance's {@link Help#footer} field.
-         * @param params Arguments referenced by the format specifiers in the footer strings
-         * @return the footer lines combined into a single String (which may be empty)
-         */
-        public String footer(final Object... params) {
-            return join(ansi(), footer, new StringBuilder(), params).toString();
-        }
-
-        /** Returns the text displayed before the header text; the result of {@code String.format(headerHeading, params)}.
-         * @param params the parameters to use to format the header heading
-         * @return the formatted header heading */
-        public String headerHeading(final Object... params) {
-            return heading(ansi(), headerHeading, params);
-        }
-
-        /** Returns the text displayed before the synopsis text; the result of {@code String.format(synopsisHeading, params)}.
-         * @param params the parameters to use to format the synopsis heading
-         * @return the formatted synopsis heading */
-        public String synopsisHeading(final Object... params) {
-            return heading(ansi(), synopsisHeading, params);
-        }
-
-        /** Returns the text displayed before the description text; an empty string if there is no description,
-         * otherwise the result of {@code String.format(descriptionHeading, params)}.
-         * @param params the parameters to use to format the description heading
-         * @return the formatted description heading */
-        public String descriptionHeading(final Object... params) {
-            return empty(descriptionHeading) ? "" : heading(ansi(), descriptionHeading, params);
-        }
-
-        /** Returns the text displayed before the positional parameter list; an empty string if there are no positional
-         * parameters, otherwise the result of {@code String.format(parameterListHeading, params)}.
-         * @param params the parameters to use to format the parameter list heading
-         * @return the formatted parameter list heading */
-        public String parameterListHeading(final Object... params) {
-            return positionalParametersFields.isEmpty() ? "" : heading(ansi(), parameterListHeading, params);
-        }
-
-        /** Returns the text displayed before the option list; an empty string if there are no options,
-         * otherwise the result of {@code String.format(optionListHeading, params)}.
-         * @param params the parameters to use to format the option list heading
-         * @return the formatted option list heading */
-        public String optionListHeading(final Object... params) {
-            return optionFields.isEmpty() ? "" : heading(ansi(), optionListHeading, params);
-        }
-
-        /** Returns the text displayed before the command list; an empty string if there are no commands,
-         * otherwise the result of {@code String.format(commandListHeading, params)}.
-         * @param params the parameters to use to format the command list heading
-         * @return the formatted command list heading */
-        public String commandListHeading(final Object... params) {
-            return commands.isEmpty() ? "" : heading(ansi(), commandListHeading, params);
-        }
-
-        /** Returns the text displayed before the footer text; the result of {@code String.format(footerHeading, params)}.
-         * @param params the parameters to use to format the footer heading
-         * @return the formatted footer heading */
-        public String footerHeading(final Object... params) {
-            return heading(ansi(), footerHeading, params);
-        }
-        /** Returns a 2-column list with command names and the first line of their header or (if absent) description.
-         * @return a usage help section describing the added commands */
-        public String commandList() {
-            if (commands.isEmpty()) {
-                return "";
-            }
-            final int commandLength = maxLength(commands.keySet());
-            final Help.TextTable textTable = new Help.TextTable(
-                    ansi(),
-                    new Help.Column(commandLength + 2, 2, Help.Column.Overflow.SPAN),
-                    new Help.Column(usageHelpWidth - (commandLength + 2), 2, Help.Column.Overflow.WRAP));
-
-            for (final Map.Entry entry : commands.entrySet()) {
-                final Help command = entry.getValue();
-                final String header = command.header != null && command.header.length > 0
-                        ? command.header[0]
-                        : (command.description != null && command.description.length > 0 ? command.description[0] : "");
-                textTable.addRowValues(colorScheme.commandText(entry.getKey()), ansi().new Text(header));
-            }
-            return textTable.toString();
-        }
-
-        private static int maxLength(final Collection any) {
-            final List strings = new ArrayList(any);
-            Collections.sort(strings, Collections.reverseOrder(Help.shortestFirst()));
-            return strings.get(0).length();
-        }
-
-        private static String join(final String[] names, final int offset, final int length, final String separator) {
-            if (names == null) {
-                return "";
-            }
-            final StringBuilder result = new StringBuilder();
-            for (int i = offset; i < offset + length; i++) {
-                result.append((i > offset) ? separator : "").append(names[i]);
-            }
-            return result.toString();
-        }
-
-        private static String stringOf(final char chr, final int length) {
-            final char[] buff = new char[length];
-            Arrays.fill(buff, chr);
-            return new String(buff);
-        }
-
-        /** Returns a {@code Layout} instance configured with the user preferences captured in this Help instance.
-         * @return a Layout */
-        public Layout createDefaultLayout() {
-            return new Layout(
-                    colorScheme,
-                    new TextTable(colorScheme.ansi()),
-                    createDefaultOptionRenderer(),
-                    createDefaultParameterRenderer());
-        }
-        /** Returns a new default OptionRenderer which converts {@link Option Options} to five columns of text to match
-         *  the default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
-         * 
-         * the required option marker 
-         * 2-character short option name (or empty string if no short option exists) 
-         * comma separator (only if both short option and long option exist, empty string otherwise) 
-         * comma-separated string with long option name(s) 
-         * first element of the {@link Option#description()} array 
-         *  
-         * Following this, there will be one row for each of the remaining elements of the {@link
-         *   Option#description()} array, and these rows look like {@code {"", "", "", "", option.description()[i]}}.
-         * If configured, this option renderer adds an additional row to display the default field value.
-         * @return a new default OptionRenderer
-         */
-        public IOptionRenderer createDefaultOptionRenderer() {
-            final DefaultOptionRenderer result = new DefaultOptionRenderer();
-            result.requiredMarker = String.valueOf(requiredOptionMarker);
-            if (showDefaultValues != null && showDefaultValues.booleanValue()) {
-                result.command = this.command;
-            }
-            return result;
-        }
-        /** Returns a new minimal OptionRenderer which converts {@link Option Options} to a single row with two columns
-         * of text: an option name and a description. If multiple names or descriptions exist, the first value is used.
-         * @return a new minimal OptionRenderer */
-        public static IOptionRenderer createMinimalOptionRenderer() {
-            return new MinimalOptionRenderer();
-        }
-
-        /** Returns a new default ParameterRenderer which converts {@link Parameters Parameters} to four columns of
-         * text to match the default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
-         * 
-         * empty string  
-         * empty string  
-         * parameter(s) label as rendered by the {@link IParamLabelRenderer} 
-         * first element of the {@link Parameters#description()} array 
-         *  
-         * Following this, there will be one row for each of the remaining elements of the {@link
-         *   Parameters#description()} array, and these rows look like {@code {"", "", "", param.description()[i]}}.
-         * If configured, this parameter renderer adds an additional row to display the default field value.
-         * @return a new default ParameterRenderer
-         */
-        public IParameterRenderer createDefaultParameterRenderer() {
-            final DefaultParameterRenderer result = new DefaultParameterRenderer();
-            result.requiredMarker = String.valueOf(requiredOptionMarker);
-            return result;
-        }
-        /** Returns a new minimal ParameterRenderer which converts {@link Parameters Parameters} to a single row with
-         * two columns of text: an option name and a description. If multiple descriptions exist, the first value is used.
-         * @return a new minimal ParameterRenderer */
-        public static IParameterRenderer createMinimalParameterRenderer() {
-            return new MinimalParameterRenderer();
-        }
-
-        /** Returns a value renderer that returns the {@code paramLabel} if defined or the field name otherwise.
-         * @return a new minimal ParamLabelRenderer */
-        public static IParamLabelRenderer createMinimalParamLabelRenderer() {
-            return new IParamLabelRenderer() {
-                @Override
-                public Text renderParameterLabel(final Field field, final Ansi ansi, final List styles) {
-                    final String text = DefaultParamLabelRenderer.renderParameterName(field);
-                    return ansi.apply(text, styles);
-                }
-
-                @Override
-                public String separator() {
-                    return "";
-                }
-            };
-        }
-        /** Returns a new default value renderer that separates option parameters from their {@linkplain Option
-         * options} with the specified separator string, surrounds optional parameters with {@code '['} and {@code ']'}
-         * characters and uses ellipses ("...") to indicate that any number of a parameter are allowed.
-         * @return a new default ParamLabelRenderer
-         */
-        public IParamLabelRenderer createDefaultParamLabelRenderer() {
-            return new DefaultParamLabelRenderer(separator);
-        }
-        /** Sorts Fields annotated with {@code Option} by their option name in case-insensitive alphabetic order. If an
-         * Option has multiple names, the shortest name is used for the sorting. Help options follow non-help options.
-         * @return a comparator that sorts fields by their option name in case-insensitive alphabetic order */
-        public static Comparator createShortOptionNameComparator() {
-            return new SortByShortestOptionNameAlphabetically();
-        }
-        /** Sorts Fields annotated with {@code Option} by their option {@linkplain Range#max max arity} first, by
-         * {@linkplain Range#min min arity} next, and by {@linkplain #createShortOptionNameComparator() option name} last.
-         * @return a comparator that sorts fields by arity first, then their option name */
-        public static Comparator createShortOptionArityAndNameComparator() {
-            return new SortByOptionArityAndNameAlphabetically();
-        }
-        /** Sorts short strings before longer strings.
-         * @return a comparators that sorts short strings before longer strings */
-        public static Comparator shortestFirst() {
-            return new ShortestFirst();
-        }
-
-        /** Returns whether ANSI escape codes are enabled or not.
-         * @return whether ANSI escape codes are enabled or not
-         */
-        public Ansi ansi() {
-            return colorScheme.ansi;
-        }
-
-        /** When customizing online help for {@link Option Option} details, a custom {@code IOptionRenderer} can be
-         * used to create textual representation of an Option in a tabular format: one or more rows, each containing
-         * one or more columns. The {@link Layout Layout} is responsible for placing these text values in the
-         * {@link TextTable TextTable}. */
-        public interface IOptionRenderer {
-            /**
-             * Returns a text representation of the specified Option and the Field that captures the option value.
-             * @param option the command line option to show online usage help for
-             * @param field the field that will hold the value for the command line option
-             * @param parameterLabelRenderer responsible for rendering option parameters to text
-             * @param scheme color scheme for applying ansi color styles to options and option parameters
-             * @return a 2-dimensional array of text values: one or more rows, each containing one or more columns
-             */
-            Text[][] render(Option option, Field field, IParamLabelRenderer parameterLabelRenderer, ColorScheme scheme);
-        }
-        /** The DefaultOptionRenderer converts {@link Option Options} to five columns of text to match the default
-         * {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
-         * 
-         * the required option marker (if the option is required) 
-         * 2-character short option name (or empty string if no short option exists) 
-         * comma separator (only if both short option and long option exist, empty string otherwise) 
-         * comma-separated string with long option name(s) 
-         * first element of the {@link Option#description()} array 
-         *  
-         * Following this, there will be one row for each of the remaining elements of the {@link
-         *   Option#description()} array, and these rows look like {@code {"", "", "", option.description()[i]}}.
-         */
-        static class DefaultOptionRenderer implements IOptionRenderer {
-            public String requiredMarker = " ";
-            public Object command;
-            private String sep;
-            private boolean showDefault;
-
-            @Override
-            public Text[][] render(
-                    final Option option,
-                    final Field field,
-                    final IParamLabelRenderer paramLabelRenderer,
-                    final ColorScheme scheme) {
-                final String[] names = ShortestFirst.sort(option.names());
-                final int shortOptionCount = names[0].length() == 2 ? 1 : 0;
-                final String shortOption = shortOptionCount > 0 ? names[0] : "";
-                sep = shortOptionCount > 0 && names.length > 1 ? "," : "";
-
-                final String longOption = join(names, shortOptionCount, names.length - shortOptionCount, ", ");
-                final Text longOptionText = createLongOptionText(field, paramLabelRenderer, scheme, longOption);
-
-                showDefault = command != null && !option.help() && !isBoolean(field.getType());
-                final Object defaultValue = createDefaultValue(field);
-
-                final String requiredOption = option.required() ? requiredMarker : "";
-                return renderDescriptionLines(
-                        option, scheme, requiredOption, shortOption, longOptionText, defaultValue);
-            }
-
-            private Object createDefaultValue(final Field field) {
-                Object defaultValue = null;
-                try {
-                    defaultValue = field.get(command);
-                    if (defaultValue == null) {
-                        showDefault = false;
-                    } // #201 don't show null default values
-                    else if (field.getType().isArray()) {
-                        final StringBuilder sb = new StringBuilder();
-                        for (int i = 0; i < Array.getLength(defaultValue); i++) {
-                            sb.append(i > 0 ? ", " : "").append(Array.get(defaultValue, i));
-                        }
-                        defaultValue = sb.insert(0, "[").append("]").toString();
-                    }
-                } catch (final Exception ex) {
-                    showDefault = false;
-                }
-                return defaultValue;
-            }
-
-            private Text createLongOptionText(
-                    final Field field,
-                    final IParamLabelRenderer renderer,
-                    final ColorScheme scheme,
-                    final String longOption) {
-                Text paramLabelText = renderer.renderParameterLabel(field, scheme.ansi(), scheme.optionParamStyles);
-
-                // if no long option, fill in the space between the short option name and the param label value
-                if (paramLabelText.length > 0 && longOption.length() == 0) {
-                    sep = renderer.separator();
-                    // #181 paramLabelText may be =LABEL or [=LABEL...]
-                    final int sepStart = paramLabelText.plainString().indexOf(sep);
-                    final Text prefix = paramLabelText.substring(0, sepStart);
-                    paramLabelText = prefix.append(paramLabelText.substring(sepStart + sep.length()));
-                }
-                Text longOptionText = scheme.optionText(longOption);
-                longOptionText = longOptionText.append(paramLabelText);
-                return longOptionText;
-            }
-
-            private Text[][] renderDescriptionLines(
-                    final Option option,
-                    final ColorScheme scheme,
-                    final String requiredOption,
-                    final String shortOption,
-                    final Text longOptionText,
-                    final Object defaultValue) {
-                final Text EMPTY = Ansi.EMPTY_TEXT;
-                final List result = new ArrayList();
-                Text[] descriptionFirstLines = scheme.ansi().new Text(str(option.description(), 0)).splitLines();
-                if (descriptionFirstLines.length == 0) {
-                    if (showDefault) {
-                        descriptionFirstLines = new Text[] {scheme.ansi().new Text("  Default: " + defaultValue)};
-                        showDefault = false; // don't show the default value twice
-                    } else {
-                        descriptionFirstLines = new Text[] {EMPTY};
-                    }
-                }
-                result.add(new Text[] {
-                    scheme.optionText(requiredOption),
-                    scheme.optionText(shortOption),
-                    scheme.ansi().new Text(sep),
-                    longOptionText,
-                    descriptionFirstLines[0]
-                });
-                for (int i = 1; i < descriptionFirstLines.length; i++) {
-                    result.add(new Text[] {EMPTY, EMPTY, EMPTY, EMPTY, descriptionFirstLines[i]});
-                }
-                for (int i = 1; i < option.description().length; i++) {
-                    final Text[] descriptionNextLines = scheme.ansi().new Text(option.description()[i]).splitLines();
-                    for (final Text line : descriptionNextLines) {
-                        result.add(new Text[] {EMPTY, EMPTY, EMPTY, EMPTY, line});
-                    }
-                }
-                if (showDefault) {
-                    result.add(
-                            new Text[] {EMPTY, EMPTY, EMPTY, EMPTY, scheme.ansi().new Text("  Default: " + defaultValue)
-                            });
-                }
-                return result.toArray(new Text[result.size()][]);
-            }
-        }
-        /** The MinimalOptionRenderer converts {@link Option Options} to a single row with two columns of text: an
-         * option name and a description. If multiple names or description lines exist, the first value is used. */
-        static class MinimalOptionRenderer implements IOptionRenderer {
-            @Override
-            public Text[][] render(
-                    final Option option,
-                    final Field field,
-                    final IParamLabelRenderer parameterLabelRenderer,
-                    final ColorScheme scheme) {
-                Text optionText = scheme.optionText(option.names()[0]);
-                final Text paramLabelText =
-                        parameterLabelRenderer.renderParameterLabel(field, scheme.ansi(), scheme.optionParamStyles);
-                optionText = optionText.append(paramLabelText);
-                return new Text[][] {
-                    {optionText, scheme.ansi().new Text(option.description().length == 0 ? "" : option.description()[0])
-                    }
-                };
-            }
-        }
-        /** The MinimalParameterRenderer converts {@link Parameters Parameters} to a single row with two columns of
-         * text: the parameters label and a description. If multiple description lines exist, the first value is used. */
-        static class MinimalParameterRenderer implements IParameterRenderer {
-            @Override
-            public Text[][] render(
-                    final Parameters param,
-                    final Field field,
-                    final IParamLabelRenderer parameterLabelRenderer,
-                    final ColorScheme scheme) {
-                return new Text[][] {
-                    {
-                        parameterLabelRenderer.renderParameterLabel(field, scheme.ansi(), scheme.parameterStyles),
-                        scheme.ansi().new Text(param.description().length == 0 ? "" : param.description()[0])
-                    }
-                };
-            }
-        }
-        /** When customizing online help for {@link Parameters Parameters} details, a custom {@code IParameterRenderer}
-         * can be used to create textual representation of a Parameters field in a tabular format: one or more rows,
-         * each containing one or more columns. The {@link Layout Layout} is responsible for placing these text
-         * values in the {@link TextTable TextTable}. */
-        public interface IParameterRenderer {
-            /**
-             * Returns a text representation of the specified Parameters and the Field that captures the parameter values.
-             * @param parameters the command line parameters to show online usage help for
-             * @param field the field that will hold the value for the command line parameters
-             * @param parameterLabelRenderer responsible for rendering parameter labels to text
-             * @param scheme color scheme for applying ansi color styles to positional parameters
-             * @return a 2-dimensional array of text values: one or more rows, each containing one or more columns
-             */
-            Text[][] render(
-                    Parameters parameters, Field field, IParamLabelRenderer parameterLabelRenderer, ColorScheme scheme);
-        }
-        /** The DefaultParameterRenderer converts {@link Parameters Parameters} to five columns of text to match the
-         * default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
-         * 
-         * the required option marker (if the parameter's arity is to have at least one value) 
-         * empty string  
-         * empty string  
-         * parameter(s) label as rendered by the {@link IParamLabelRenderer} 
-         * first element of the {@link Parameters#description()} array 
-         *  
-         * Following this, there will be one row for each of the remaining elements of the {@link
-         *   Parameters#description()} array, and these rows look like {@code {"", "", "", param.description()[i]}}.
-         */
-        static class DefaultParameterRenderer implements IParameterRenderer {
-            public String requiredMarker = " ";
-
-            @Override
-            public Text[][] render(
-                    final Parameters params,
-                    final Field field,
-                    final IParamLabelRenderer paramLabelRenderer,
-                    final ColorScheme scheme) {
-                final Text label =
-                        paramLabelRenderer.renderParameterLabel(field, scheme.ansi(), scheme.parameterStyles);
-                final Text requiredParameter =
-                        scheme.parameterText(Range.parameterArity(field).min > 0 ? requiredMarker : "");
-
-                final Text EMPTY = Ansi.EMPTY_TEXT;
-                final List result = new ArrayList();
-                Text[] descriptionFirstLines = scheme.ansi().new Text(str(params.description(), 0)).splitLines();
-                if (descriptionFirstLines.length == 0) {
-                    descriptionFirstLines = new Text[] {EMPTY};
-                }
-                result.add(new Text[] {requiredParameter, EMPTY, EMPTY, label, descriptionFirstLines[0]});
-                for (int i = 1; i < descriptionFirstLines.length; i++) {
-                    result.add(new Text[] {EMPTY, EMPTY, EMPTY, EMPTY, descriptionFirstLines[i]});
-                }
-                for (int i = 1; i < params.description().length; i++) {
-                    final Text[] descriptionNextLines = scheme.ansi().new Text(params.description()[i]).splitLines();
-                    for (final Text line : descriptionNextLines) {
-                        result.add(new Text[] {EMPTY, EMPTY, EMPTY, EMPTY, line});
-                    }
-                }
-                return result.toArray(new Text[result.size()][]);
-            }
-        }
-        /** When customizing online usage help for an option parameter or a positional parameter, a custom
-         * {@code IParamLabelRenderer} can be used to render the parameter name or label to a String. */
-        public interface IParamLabelRenderer {
-
-            /** Returns a text rendering of the Option parameter or positional parameter; returns an empty string
-             * {@code ""} if the option is a boolean and does not take a parameter.
-             * @param field the annotated field with a parameter label
-             * @param ansi determines whether ANSI escape codes should be emitted or not
-             * @param styles the styles to apply to the parameter label
-             * @return a text rendering of the Option parameter or positional parameter */
-            Text renderParameterLabel(Field field, Ansi ansi, List styles);
-
-            /** Returns the separator between option name and param label.
-             * @return the separator between option name and param label */
-            String separator();
-        }
-        /**
-         * DefaultParamLabelRenderer separates option parameters from their {@linkplain Option options} with a
-         * {@linkplain DefaultParamLabelRenderer#separator separator} string, surrounds optional values
-         * with {@code '['} and {@code ']'} characters and uses ellipses ("...") to indicate that any number of
-         * values is allowed for options or parameters with variable arity.
-         */
-        static class DefaultParamLabelRenderer implements IParamLabelRenderer {
-            /** The string to use to separate option parameters from their options. */
-            public final String separator;
-            /** Constructs a new DefaultParamLabelRenderer with the specified separator string. */
-            public DefaultParamLabelRenderer(final String separator) {
-                this.separator = Assert.notNull(separator, "separator");
-            }
-
-            @Override
-            public String separator() {
-                return separator;
-            }
-
-            @Override
-            public Text renderParameterLabel(final Field field, final Ansi ansi, final List