class ListItem extends ArrayList<Item>implements Item {
        
        /** The Constant serialVersionUID. */
        private static final long serialVersionUID = 1L;

        /* (non-Javadoc)
         * @see org.hotswap.agent.versions.ComparableVersion.Item#getType()
         */
        public int getType() {
            return LIST_ITEM;
        }

        /* (non-Javadoc)
         * @see org.hotswap.agent.versions.ComparableVersion.Item#isNull()
         */
        public boolean isNull() {
            return (size() == 0);
        }

        /**
         * Normalize.
         */
        void normalize() {
            for (int i = size() - 1; i >= 0; i--) {
                Item lastItem = get(i);

                if (lastItem.isNull()) {
                    // remove null trailing items: 0, "", empty list
                    remove(i);
                } else if (!(lastItem instanceof ListItem)) {
                    break;
                }
            }
        }

        /* (non-Javadoc)
         * @see org.hotswap.agent.versions.ComparableVersion.Item#compareTo(org.hotswap.agent.versions.ComparableVersion.Item)
         */
        public int compareTo(Item item) {
            if (item == null) {
                if (size() == 0) {
                    return 0; // 1-0 = 1- (normalize) = 1
                }
                Item first = get(0);
                return first.compareTo(null);
            }
            switch (item.getType()) {
            case INTEGER_ITEM:
                return -1; // 1-1 < 1.0.x

            case STRING_ITEM:
                return 1; // 1-1 > 1-sp

            case LIST_ITEM:
                Iterator<Item> left = iterator();
                Iterator<Item> right = ((ListItem) item).iterator();

                while (left.hasNext() || right.hasNext()) {
                    Item l = left.hasNext() ? left.next() : null;
                    Item r = right.hasNext() ? right.next() : null;

                    // if this is shorter, then invert the compare and mul with
                    // -1
                    int result = l == null ? (r == null ? 0 : -1 * r.compareTo(l)) : l.compareTo(r);

                    if (result != 0) {
                        return result;
                    }
                }

                return 0;

            default:
                throw new RuntimeException("invalid item: " + item.getClass());
            }
        }

        /* (non-Javadoc)
         * @see java.util.AbstractCollection#toString()
         */
        public String toString() {
            StringBuilder buffer = new StringBuilder();
            for (Item item : this) {
                if (buffer.length() > 0) {
                    buffer.append((item instanceof ListItem) ? '-' : '.');
                }
                buffer.append(item);
            }
            return buffer.toString();
        }
    }

    /**
     * Instantiates a new comparable version.
     *
     * @param version the version
     */
    public ComparableVersion(String version) {
        parseVersion(version);
    }

    /**
     * Parses the version.
     *
     * @param version the version
     */
    public final void parseVersion(String version) {
        this.value = version;

        items = new ListItem();

        version = version.toLowerCase(Locale.ENGLISH);

        ListItem list = items;

        Stack<Item> stack = new Stack<>();
        stack.push(list);

        boolean isDigit = false;

        int startIndex = 0;

        for (int i = 0; i < version.length(); i++) {
            char c = version.charAt(i);

            if (c == '.') {
                if (i == startIndex) {
                    list.add(IntegerItem.ZERO);
                } else {
                    list.add(parseItem(isDigit, version.substring(startIndex, i)));
                }
                startIndex = i + 1;
            } else if (c == '-') {
                if (i == startIndex) {
                    list.add(IntegerItem.ZERO);
                } else {
                    list.add(parseItem(isDigit, version.substring(startIndex, i)));
                }
                startIndex = i + 1;

                list.add(list = new ListItem());
                stack.push(list);
            } else if (Character.isDigit(c)) {
                if (!isDigit && i > startIndex) {
                    list.add(new StringItem(version.substring(startIndex, i), true));
                    startIndex = i;

                    list.add(list = new ListItem());
                    stack.push(list);
                }

                isDigit = true;
            } else {
                if (isDigit && i > startIndex) {
                    list.add(parseItem(true, version.substring(startIndex, i)));
                    startIndex = i;

                    list.add(list = new ListItem());
                    stack.push(list);
                }

                isDigit = false;
            }
        }

        if (version.length() > startIndex) {
            list.add(parseItem(isDigit, version.substring(startIndex)));
        }

        while (!stack.isEmpty()) {
            list = (ListItem) stack.pop();
            list.normalize();
        }

        canonical = items.toString();
    }

    /**
     * Parses the item.
     *
     * @param isDigit the is digit
     * @param buf the buf
     * @return the item
     */
    private static Item parseItem(boolean isDigit, String buf) {
        return isDigit ? new IntegerItem(buf) : new StringItem(buf, false);
    }

    /* (non-Javadoc)
     * @see java.lang.Comparable#compareTo(java.lang.Object)
     */
    public int compareTo(ComparableVersion o) {
        return items.compareTo(o.items);
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    public String toString() {
        return value;
    }

    /**
     * Gets the canonical.
     *
     * @return the canonical
     */
    public String getCanonical() {
        return canonical;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    public boolean equals(Object o) {
        return (o instanceof ComparableVersion) && canonical.equals(ComparableVersion.class.cast(o).canonical);
    }

    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    public int hashCode() {
        return canonical.hashCode();
    }

    /**
     * Main to test version parsing and comparison.
     *
     * @param args
     *            the version strings to parse and compare
     */
    public static void main(String... args) {<FILL_FUNCTION_BODY>

        System.out.println("Display parameters as parsed by Maven (in canonical form) and comparison result:");
        if (args.length == 0) {
            return;
        }

        ComparableVersion prev = null;
        int i = 1;
        for (String version : args) {
            ComparableVersion c = new ComparableVersion(version);

            if (prev != null) {
                int compare = prev.compareTo(c);
                System.out.println("   " + prev.toString() + ' ' + ((compare == 0) ? "==" : ((compare < 0) ? "<" : ">")) + ' ' + version);
            }

            System.out.println(String.valueOf(i++) + ". " + version + " == " + c.getCanonical());

            prev = c;
        }
    
<no_super_class>