func (b *Builder) Table(table [][]string, align []TableAlignment) *Builder {
	if len(table) < 2 {
		return b
	}
	idxAlign := func(idx int) TableAlignment {
		alen := len(align)
		if alen == 0 || idx > alen-1 {
			return defaultAlign
		}
		return align[idx]
	}
	headerLen := len(table[0])
	colsLens := make([]int, headerLen)
	for x, line := range table {
		for y := range line {
			cl := max(charLen(table[x][y]), colsLens[y])
			if cl < minCellSize {
				colsLens[y] = minCellSize
			} else {
				colsLens[y] = cl
			}
		}
	}
	sb := strings.Builder{}
	for x, line := range table {
		if x == 1 {
			var cols []string
			for j, l := range colsLens {
				switch idxAlign(j) {
				case AlignRight:
					cols = append(cols, fmt.Sprintf("%s:", strings.Repeat("-", l-1)))
				case AlignCenter:
					cols = append(cols, fmt.Sprintf(":%s:", strings.Repeat("-", l-2)))
				case AlignLeft:  
					cols = append(cols, strings.Repeat("-", l))
				}
			}
			sb.WriteString(joinCols(cols))
			sb.WriteByte('\n')
		}
		cols := make([]string, len(table[0]))
		for y, cl := range colsLens {
			var cell string
			if y <= len(line)-1 {
				cell = line[y]
			}
			if cell == "" {
				cols[y] = strings.Repeat(" ", cl)
			} else {
				cell = reCRLN.ReplaceAllString(cell, " ")
				cols[y] = padSpaces(cell, cl, idxAlign(y))
			}
		}
		sb.WriteString(joinCols(cols))
		sb.WriteByte('\n')
	}
	b.writeln(sb.String())
	return b
}
Table adds a table from the given two-dimensional interface
array to the markdown content.
The first row of the array is considered as the table header.
Align represents the alignment of each column, left to right.
If the alignment of a column is not defined, the rigth alignment
will be used instead as default.
package markdown
import (
	"fmt"
	"math"
	"regexp"
	"strings"
	"golang.org/x/text/unicode/norm"
)
type TableAlignment uint8
const (
	AlignLeft TableAlignment = iota
	AlignCenter
	AlignRight
)
var reCRLN = regexp.MustCompile(`\r?\n`)
type Builder struct {
	markdown string
}
func (b *Builder) String() string {
	return strings.TrimSpace(b.nl().markdown)
}
func (b *Builder) Block() *Builder {
	return new(Builder)
}
func (b *Builder) Line(text string) *Builder {
	return b.write(text)
}
func (b *Builder) P(text string) *Builder {
	return b.writeln(text).nl()
}
func (b *Builder) H1(text string) *Builder {
	return b.writeln(header(text, 1)).nl()
}
func (b *Builder) H2(text string) *Builder {
	return b.writeln(header(text, 2)).nl()
}
func (b *Builder) H3(text string) *Builder {
	return b.writeln(header(text, 3)).nl()
}
func (b *Builder) H4(text string) *Builder {
	return b.writeln(header(text, 4)).nl()
}
func (b *Builder) H5(text string) *Builder {
	return b.writeln(header(text, 5)).nl()
}
func (b *Builder) H6(text string) *Builder {
	return b.writeln(header(text, 6)).nl()
}
func header(text string, level int) string {
	text = reCRLN.ReplaceAllString(text, " ")
	return fmt.Sprintf("%s %s", strings.Repeat("#", level), strings.TrimSpace(text))
}
func (b *Builder) nl() *Builder {
	return b.write("\n")
}
func (b *Builder) AltH1(header string) *Builder {
	header = reCRLN.ReplaceAllString(header, " ")
	header = strings.TrimSpace(header)
	return b.writeln(header).writeln(strings.Repeat("=", charLen(header))).nl()
}
func (b *Builder) AltH2(header string) *Builder {
	header = reCRLN.ReplaceAllString(header, " ")
	header = strings.TrimSpace(header)
	return b.writeln(header).writeln(strings.Repeat("-", charLen(header))).nl()
}
func (b *Builder) HR() *Builder {
	return b.P("---------------------------------------")
}
func (b *Builder) BR() *Builder {
	return b.write("   \n")
}
func (b *Builder) InlineCode(code string) string {
	return fmt.Sprintf("`%s`", code)
}
func (b *Builder) Code(code, lang string) *Builder {
	return b.
		writelnf("```%s", lang).
		writeln(code).
		writeln("```").
		nl()
}
func (b *Builder) Emphasis(text string) string {
	return b.Italic(text)
}
func (b *Builder) Italic(text string) string {
	return fmt.Sprintf("*%s*", text)
}
func (b *Builder) StrongEmphasis(text string) string {
	return b.Bold(text)
}
func (b *Builder) Bold(text string) string {
	return fmt.Sprintf("**%s**", text)
}
func (b *Builder) CombinedEmphasis(text string) string {
	return fmt.Sprintf("**_%s_**", text)
}
func (b *Builder) Strikethrough(text string) string {
	return fmt.Sprintf("~~%s~~", text)
}
func (b *Builder) Link(url, title string) string {
	return fmt.Sprintf("[%s](%s)", title, url)
}
func (b *Builder) Image(url, title string) string {
	return fmt.Sprintf("![%s](%s)", title, url)
}
func (b *Builder) Blockquote(text string) *Builder {
	lines := strings.Split(text, "\n")
	var newLines []string
	for _, l := range lines {
		newLines = append(newLines, strings.TrimSpace(">  "+l))
	}
	content := strings.Join(newLines, "\n")
	return b.P(content)
}
func (b *Builder) BulletedList(list ...interface{}) *Builder {
	for _, el := range list {
		lines := strings.Split(fmt.Sprintf("%s", el), "\n")
		for i, l := range lines {
			if i == 0 {
				b.writelnf("* %s", l)
			} else {
				b.writelnf("  %s", l)
			}
		}
	}
	return b.nl()
}
func (b *Builder) NumberedList(list ...interface{}) *Builder {
	for i, el := range list {
		lines := strings.Split(fmt.Sprintf("%s", el), "\n")
		for j, l := range lines {
			if j == 0 {
				b.writelnf("%d. %s", i+1, l)
			} else {
				b.writelnf("   %s", l)
			}
		}
	}
	return b.nl()
}
const (
	minCellSize  = 3
	defaultAlign = AlignLeft
)