@@ -0,0 +1,3078 @@
+package net.darkhax.bookshelf.api.lib;%0A%0Aimport org.apache.commons.lang3.StringUtils;%0A%0Aimport java.util.LinkedList;%0Aimport java.util.List;%0Aimport java.util.function.Function;%0A%0Apublic class TableBuilder%3CT%3E %7B%0A%0A    private static final String NEW_LINE = System.lineSeparator();%0A%0A    private static final String DIVIDER_COLUMN = %22%7C%22;%0A%0A    private static final String DIVIDER_ROW = %22-%22;%0A%0A    private final List%3CTableColumn%3CT%3E%3E columns = new LinkedList%3C%3E();%0A    private int entryCount = 0;%0A%0A    public TableBuilder%3CT%3E addColumn(String name, Function%3CT, Object%3E function) %7B%0A%0A        this.columns.add(new TableColumn%3C%3E(name, function));%0A        return this;%0A    %7D%0A%0A    public void addAll(Iterable%3CT%3E entries) %7B%0A%0A        entries.forEach(this::addEntry);%0A    %7D%0A%0A    public void addEntry(T entry) %7B%0A%0A        columns.forEach(column -%3E column.processValue(entry));%0A        entryCount++;%0A    %7D%0A%0A    @Override%0A    public String toString() %7B%0A%0A        final StringBuilder builder = new StringBuilder();%0A%0A        // Column Names%0A        for (TableColumn%3CT%3E column : this.columns) %7B%0A%0A            builder.append(DIVIDER_COLUMN).append(%22 %22).append(StringUtils.rightPad(column.getTitle(), column.getMaxLength())).append(%22 %22);%0A        %7D%0A%0A        builder.append(DIVIDER_COLUMN).append(NEW_LINE);%0A%0A        // Entry Separator%0A        for (TableColumn%3CT%3E column : this.columns) %7B%0A%0A            builder.append(DIVIDER_COLUMN).append(DIVIDER_ROW.repeat(column.getMaxLength() + 2));%0A        %7D%0A%0A        builder.append(DIVIDER_COLUMN).append(NEW_LINE);%0A%0A        for (int entryIndex = 0; entryIndex %3C entryCount; entryIndex++) %7B%0A%0A            for (TableColumn%3CT%3E column : this.columns) %7B%0A%0A                builder.append(DIVIDER_COLUMN).append(%22 %22).append(StringUtils.rightPad(column.getValue(entryIndex), column.getMaxLength())).append(%22 %22);%0A            %7D%0A%0A            builder.append(DIVIDER_COLUMN);%0A%0A            if (entryIndex != entryCount - 1) %7B%0A%0A                builder.append(NEW_LINE);%0A            %7D%0A        %7D%0A%0A        return builder.toString();%0A    %7D%0A%0A    public static class TableColumn%3CT%3E %7B%0A%0A        private final String title;%0A        private final Function%3CT, Object%3E valueResolver;%0A        private final List%3CString%3E heldValues;%0A        private int maxLength;%0A%0A        public TableColumn(String title, Function%3CT, Object%3E valueResolver) %7B%0A%0A            this.title = title;%0A            this.valueResolver = valueResolver;%0A            this.heldValues = new LinkedList%3C%3E();%0A            this.maxLength = this.title.length();%0A        %7D%0A%0A        public String getTitle() %7B%0A%0A            return this.title;%0A        %7D%0A%0A        public String getValue(int index) %7B%0A%0A            return this.heldValues.get(index);%0A        %7D%0A%0A        public void processValue(T value) %7B%0A%0A            final String valueText = String.valueOf(this.valueResolver.apply(value));%0A            heldValues.add(valueText);%0A%0A            if (valueText.length() %3E maxLength) %7B%0A%0A                this.maxLength = valueText.length();%0A            %7D%0A        %7D%0A%0A        public int getMaxLength() %7B%0A%0A            return this.maxLength;%0A        %7D%0A    %7D%0A%7D

Reimplement markdown table builder.